xlwings-server 1.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- xlwings_server/.env.template +145 -0
- xlwings_server/__init__.py +12 -0
- xlwings_server/_version.py +34 -0
- xlwings_server/auth/__init__.py +0 -0
- xlwings_server/auth/custom/__init__.py +26 -0
- xlwings_server/auth/entraid/__init__.py +131 -0
- xlwings_server/auth/entraid/jwks.py +10 -0
- xlwings_server/azure_functions_templates/.funcignore +28 -0
- xlwings_server/azure_functions_templates/function_app.py +28 -0
- xlwings_server/azure_functions_templates/host.json +22 -0
- xlwings_server/azure_functions_templates/local.settings.json +8 -0
- xlwings_server/build_utils/__init__.py +9 -0
- xlwings_server/build_utils/static_file_hasher.py +212 -0
- xlwings_server/cli.py +1592 -0
- xlwings_server/config.py +228 -0
- xlwings_server/custom_functions/__init__.py +8 -0
- xlwings_server/custom_functions/examples.py +177 -0
- xlwings_server/custom_scripts/__init__.py +8 -0
- xlwings_server/custom_scripts/examples.py +94 -0
- xlwings_server/databases.py +19 -0
- xlwings_server/dependencies.py +126 -0
- xlwings_server/docker_templates/.dockerignore +15 -0
- xlwings_server/docker_templates/Dockerfile +60 -0
- xlwings_server/docker_templates/docker-compose.yaml +32 -0
- xlwings_server/hotreload.py +59 -0
- xlwings_server/main.py +242 -0
- xlwings_server/models/__init__.py +14 -0
- xlwings_server/models/user.py +53 -0
- xlwings_server/object_handles.py +142 -0
- xlwings_server/routers/__init__.py +0 -0
- xlwings_server/routers/manifest.py +82 -0
- xlwings_server/routers/root.py +16 -0
- xlwings_server/routers/socketio.py +69 -0
- xlwings_server/routers/taskpane.py +12 -0
- xlwings_server/routers/xlwings.py +197 -0
- xlwings_server/security_headers.json +53 -0
- xlwings_server/serializers/__init__.py +25 -0
- xlwings_server/serializers/default_serializer.py +19 -0
- xlwings_server/serializers/dictionary_serializer.py +25 -0
- xlwings_server/serializers/framework.py +50 -0
- xlwings_server/serializers/numpy_serializer.py +26 -0
- xlwings_server/serializers/pandas_serializer.py +95 -0
- xlwings_server/static/css/core.css +28 -0
- xlwings_server/static/css/style.css +0 -0
- xlwings_server/static/images/favicon.png +0 -0
- xlwings_server/static/images/xlwings-16.png +0 -0
- xlwings_server/static/images/xlwings-32.png +0 -0
- xlwings_server/static/images/xlwings-64.png +0 -0
- xlwings_server/static/images/xlwings-80.png +0 -0
- xlwings_server/static/js/auth.js +13 -0
- xlwings_server/static/js/config.js +4 -0
- xlwings_server/static/js/core/alpinejs-csp-boilerplate.js +11 -0
- xlwings_server/static/js/core/bootstrap-customizations.js +7 -0
- xlwings_server/static/js/core/custom-functions-code.js +296 -0
- xlwings_server/static/js/core/examples.js +62 -0
- xlwings_server/static/js/core/hotreload.js +3 -0
- xlwings_server/static/js/core/htmx-handlers.js +86 -0
- xlwings_server/static/js/core/officejs-history-fix-part1.js +3 -0
- xlwings_server/static/js/core/officejs-history-fix-part2.js +2 -0
- xlwings_server/static/js/core/reload-custom-functions.js +79 -0
- xlwings_server/static/js/core/socketio-handlers.js +34 -0
- xlwings_server/static/js/core/xlwings-alert.js +22 -0
- xlwings_server/static/js/core/xlwingsjs/alert.js +85 -0
- xlwings_server/static/js/core/xlwingsjs/auth.js +63 -0
- xlwings_server/static/js/core/xlwingsjs/sheet-buttons.js +133 -0
- xlwings_server/static/js/core/xlwingsjs/utils.js +119 -0
- xlwings_server/static/js/core/xlwingsjs/wasm.js +131 -0
- xlwings_server/static/js/core/xlwingsjs/xlwings.js +1060 -0
- xlwings_server/static/js/main.js +0 -0
- xlwings_server/static/js/ribbon.js +17 -0
- xlwings_server/static/vendor/@alpinejs/LICENSE +21 -0
- xlwings_server/static/vendor/@alpinejs/csp/dist/cdn.min.js +7 -0
- xlwings_server/static/vendor/@microsoft/office-js/LICENSE.md +76 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/af-za/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/agaveerrorux.js +18 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/images/agavedefaulticon32x32.png +0 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/images/agavedefaulticon96x96.png +0 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/images/businessbarclose_16x16x32.png +0 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/images/dropdownarrow_16x16x32.png +0 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/images/ellipsis_16x16x32.png +0 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/images/miniinfoblue_16x16x32.png +0 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/images/moe_default_icon.png +0 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/images/moe_status_icons.png +0 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/images/office.png +0 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/images/refresh_16x16x32.png +0 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/index.html +16 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/style/agaveerrorux.css +482 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/am-et/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/ar-ae/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/ar-bh/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/ar-dz/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/ar-eg/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/ar-iq/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/ar-jo/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/ar-kw/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/ar-lb/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/ar-ly/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/ar-ma/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/ar-om/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/ar-qa/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/ar-sa/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/ar-sy/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/ar-tn/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/ar-ye/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/ariatelemetry/aria-web-telemetry-2.8.0.min.js +2 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/ariatelemetry/aria-web-telemetry-2.9.0.min.js +2 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/ariatelemetry/aria-web-telemetry.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/az-latn-az/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/be-by/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/bg-bg/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/bn-in/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/bs-latn-ba/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/ca-es/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/cs-cz/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/cy-gb/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/da-dk/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/de-at/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/de-ch/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/de-de/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/de-li/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/de-lu/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/el-gr/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/en-029/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/en-au/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/en-bz/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/en-ca/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/en-gb/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/en-ie/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/en-in/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/en-jm/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/en-my/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/en-nz/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/en-ph/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/en-sg/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/en-tt/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/en-us/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/en-za/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/en-zw/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/es-ar/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/es-bo/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/es-cl/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/es-co/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/es-cr/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/es-do/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/es-ec/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/es-es/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/es-gt/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/es-hn/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/es-mx/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/es-ni/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/es-pa/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/es-pe/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/es-pr/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/es-py/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/es-sv/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/es-us/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/es-uy/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/es-ve/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/es6-promise.js +5 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/et-ee/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/eu-es/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/excel-15.01.js +11 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/excel-15.02.js +11 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/excel-15.js +11 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/excel-mac-16.00-core.js +11 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/excel-mac-16.00.js +25 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/excel-web-16.00-core.js +11 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/excel-web-16.00.js +25 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/excel-win32-16.00.js +19 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/excel-win32-16.01-core.js +11 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/excel-win32-16.01.js +25 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/excel-winrt-16.00.js +25 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/excelios-15.js +11 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/excelwebapp-15.01.js +11 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/excelwebapp-15.02.js +11 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/excelwebapp-15.js +11 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/fa-ir/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/fi-fi/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/fil-ph/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/fr-be/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/fr-ca/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/fr-ch/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/fr-fr/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/fr-lu/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/fr-mc/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/ga-ie/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/gl-es/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/gu-in/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/he-il/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/hi-in/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/hr-ba/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/hr-hr/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/html2canvas.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/hu-hu/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/hy-am/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/id-id/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/is-is/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/it-ch/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/it-it/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/ja-jp/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/ka-ge/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/kk-kz/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/km-kh/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/kn-in/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/ko-kr/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/lb-lu/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/lo-la/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/lt-lt/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/lv-lv/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/mk-mk/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/ml-in/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/mn-mn/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/mr-in/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/ms-bn/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/ms-my/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/mt-mt/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/nb-no/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/ne-np/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/nl-be/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/nl-nl/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/nn-no/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/o15apptofilemappingtable.js +11 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/office-vsdoc.js +28596 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/office.js +84 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/pl-pl/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/pt-br/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/pt-pt/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/ro-ro/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/ru-ru/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/si-lk/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/sk-sk/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/sl-si/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/sq-al/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/sr-cyrl-cs/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/sr-cyrl-rs/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/sr-latn-cs/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/sr-latn-rs/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/sv-fi/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/sv-se/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/sw-ke/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/ta-in/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/te-in/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/telemetry/oteljs.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/telemetry/oteljs_agave.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/th-th/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/tr-tr/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/uk-ua/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/ur-pk/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/vi-vn/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/webauth/webauth.browserauth.js +77 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/webauth/webauth.implicit.js +35 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/zh-cn/office_strings.js +1 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/zh-hk/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/zh-mo/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/zh-sg/office_strings.js +8 -0
- xlwings_server/static/vendor/@microsoft/office-js/dist/zh-tw/office_strings.js +1 -0
- xlwings_server/static/vendor/axios/dist/axios.min.js +3 -0
- xlwings_server/static/vendor/axios/dist/axios.min.js.map +1 -0
- xlwings_server/static/vendor/bootstrap/LICENSE +21 -0
- xlwings_server/static/vendor/bootstrap/dist/js/bootstrap.bundle.min.js +7 -0
- xlwings_server/static/vendor/bootstrap/dist/js/bootstrap.bundle.min.js.map +1 -0
- xlwings_server/static/vendor/bootstrap-xlwings/dist/bootstrap-xlwings.min.css +12 -0
- xlwings_server/static/vendor/bootstrap-xlwings/dist/bootstrap-xlwings.min.css.map +1 -0
- xlwings_server/static/vendor/htmx-ext-head-support/head-support.js +144 -0
- xlwings_server/static/vendor/htmx-ext-loading-states/loading-states.js +184 -0
- xlwings_server/static/vendor/htmx.org/LICENSE +13 -0
- xlwings_server/static/vendor/htmx.org/dist/htmx.min.js +1 -0
- xlwings_server/static/vendor/socket.io/LICENSE +22 -0
- xlwings_server/static/vendor/socket.io/client-dist/socket.io.min.js +7 -0
- xlwings_server/static/vendor/socket.io/client-dist/socket.io.min.js.map +1 -0
- xlwings_server/templates/_book.html +8 -0
- xlwings_server/templates/alert_base.html +16 -0
- xlwings_server/templates/base.html +117 -0
- xlwings_server/templates/examples/alpine/README.md +26 -0
- xlwings_server/templates/examples/alpine/taskpane.html +47 -0
- xlwings_server/templates/examples/auth/README.md +38 -0
- xlwings_server/templates/examples/auth/protected.html +8 -0
- xlwings_server/templates/examples/auth/public.html +11 -0
- xlwings_server/templates/examples/excel_object_model/README.md +49 -0
- xlwings_server/templates/examples/excel_object_model/add_name_form.html +27 -0
- xlwings_server/templates/examples/hello_world/README.md +9 -0
- xlwings_server/templates/examples/hello_world/taskpane_hello.html +24 -0
- xlwings_server/templates/examples/htmx_form/README.md +44 -0
- xlwings_server/templates/examples/htmx_form/_greeting.html +6 -0
- xlwings_server/templates/examples/htmx_form/taskpane_htmx_form.html +21 -0
- xlwings_server/templates/examples/live_form_validation/README.md +60 -0
- xlwings_server/templates/examples/live_form_validation/add_name_form.html +33 -0
- xlwings_server/templates/examples/multi_app/README.md +34 -0
- xlwings_server/templates/examples/multi_app/taskpane1.html +7 -0
- xlwings_server/templates/examples/multi_app/taskpane2.html +7 -0
- xlwings_server/templates/examples/multi_app/taskpane_loader.html +5 -0
- xlwings_server/templates/examples/navigation/README.md +28 -0
- xlwings_server/templates/examples/navigation/_navigation.html +16 -0
- xlwings_server/templates/examples/navigation/taskpane_one.html +8 -0
- xlwings_server/templates/examples/navigation/taskpane_three.html +8 -0
- xlwings_server/templates/examples/navigation/taskpane_two.html +8 -0
- xlwings_server/templates/examples/pictures/README.md +42 -0
- xlwings_server/templates/examples/pictures/_picture.html +4 -0
- xlwings_server/templates/examples/pictures/taskpane_pictures.html +26 -0
- xlwings_server/templates/manifest.xml +155 -0
- xlwings_server/templates/taskpane.html +1 -0
- xlwings_server/templates/xlwings_alert.html +27 -0
- xlwings_server/templates.py +61 -0
- xlwings_server/utils.py +32 -0
- xlwings_server/wasm/__init__.py +0 -0
- xlwings_server/wasm/config.py +24 -0
- xlwings_server/wasm/main.py +236 -0
- xlwings_server/wasm/requirements.txt +5 -0
- xlwings_server-1.1.0.dist-info/METADATA +61 -0
- xlwings_server-1.1.0.dist-info/RECORD +313 -0
- xlwings_server-1.1.0.dist-info/WHEEL +4 -0
- xlwings_server-1.1.0.dist-info/entry_points.txt +2 -0
- xlwings_server-1.1.0.dist-info/licenses/LICENSE.md +223 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head hx-head="merge">
|
|
4
|
+
{% block head %}
|
|
5
|
+
<meta charset="utf-8" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
7
|
+
<title>Task pane</title>
|
|
8
|
+
<link rel="icon" type="image/png" href="{{ url_for('static', path='/images/favicon.png') }}" />
|
|
9
|
+
{# xlwings Wasm #}
|
|
10
|
+
{% if settings.enable_wasm %}
|
|
11
|
+
{% if settings.cdn_pyodide %}
|
|
12
|
+
<script
|
|
13
|
+
src="https://cdn.jsdelivr.net/pyodide/v0.27.5/full/pyodide.js"
|
|
14
|
+
integrity="sha384-rm4QcPMX69sqmX2kWiJa3BF02sgdJkVyATWkw5NHAxBUAvmLXhToWZYaP2wCcyEe"
|
|
15
|
+
crossorigin="anonymous"></script>
|
|
16
|
+
{% else %}
|
|
17
|
+
<script src="{{ url_for('static', path='/vendor/pyodide/pyodide.js') }}"></script>
|
|
18
|
+
{% endif %}
|
|
19
|
+
{% endif %}
|
|
20
|
+
{# Config #}
|
|
21
|
+
<script src="{{ url_for('static', path='/js/config.js') }}" defer></script>
|
|
22
|
+
{# htmx #}
|
|
23
|
+
{% if settings.enable_htmx %}
|
|
24
|
+
<script src="{{ url_for('static', path='/vendor/htmx.org/dist/htmx.min.js') }}"></script>
|
|
25
|
+
<script src="{{ url_for('static', path='/vendor/htmx-ext-head-support/head-support.js') }}"></script>
|
|
26
|
+
<script src="{{ url_for('static', path='/vendor/htmx-ext-loading-states/loading-states.js') }}"></script>
|
|
27
|
+
<script src="{{ url_for('static', path='/js/core/htmx-handlers.js') }}" defer></script>
|
|
28
|
+
{% endif %}
|
|
29
|
+
<script src="{{ url_for('static', path='/js/core/officejs-history-fix-part1.js') }}"></script>
|
|
30
|
+
{# Office.js #}
|
|
31
|
+
{% if settings.cdn_officejs %}
|
|
32
|
+
<script src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js"></script>
|
|
33
|
+
{% else %}
|
|
34
|
+
<script src="{{ url_for('static', path='/vendor/@microsoft/office-js/dist/office.js') }}"></script>
|
|
35
|
+
{% endif %}
|
|
36
|
+
<script src="{{ url_for('static', path='/js/core/officejs-history-fix-part2.js') }}"></script>
|
|
37
|
+
{# Socket.io (must come before xlwings.js) #}
|
|
38
|
+
{% block socketio %}
|
|
39
|
+
{% if settings.enable_socketio %}
|
|
40
|
+
<script src="{{ url_for('static', path='/vendor/socket.io/client-dist/socket.io.min.js') }}"></script>
|
|
41
|
+
{% endif %}
|
|
42
|
+
{% endblock socketio %}
|
|
43
|
+
{# xlwings.js (must come before custom-function-code) #}
|
|
44
|
+
<script type="module" src="{{ url_for('static', path='/js/core/xlwingsjs/xlwings.js') }}" defer></script>
|
|
45
|
+
{% block socketio2 %}
|
|
46
|
+
{% if settings.enable_socketio %}
|
|
47
|
+
{# Must come after xlwings.js #}
|
|
48
|
+
<script src="{{ url_for('static', path='/js/core/socketio-handlers.js') }}" defer></script>
|
|
49
|
+
{% endif %}
|
|
50
|
+
{% endblock socketio2 %}
|
|
51
|
+
{# Alpine.js CSP boilerplate (must come before custom JS, which must come before alpinejs library) #}
|
|
52
|
+
{% if settings.enable_alpinejs_csp %}
|
|
53
|
+
<script src="{{ url_for('static', path='/js/core/alpinejs-csp-boilerplate.js') }}"></script>
|
|
54
|
+
{% endif %}
|
|
55
|
+
{# JS Config #}
|
|
56
|
+
{# prettier-ignore-start #}
|
|
57
|
+
<script id="config" type="application/json">
|
|
58
|
+
{{ settings.jsconfig|tojson }}
|
|
59
|
+
</script>
|
|
60
|
+
{# prettier-ignore-end #}
|
|
61
|
+
<script src="{{ url_for('static', path='/js/auth.js') }}"></script>
|
|
62
|
+
{% block custom_functions_code %}
|
|
63
|
+
<script src="{{ url_for('custom_functions_code') }}" defer></script>
|
|
64
|
+
{% if settings.environment == "dev" or settings.enable_wasm %}
|
|
65
|
+
<script src="{{ url_for('static', path='/js/core/reload-custom-functions.js') }}" defer></script>
|
|
66
|
+
{% endif %}
|
|
67
|
+
{% endblock custom_functions_code %}
|
|
68
|
+
{# Bootstrap with the xlwings theme #}
|
|
69
|
+
{% if settings.enable_bootstrap %}
|
|
70
|
+
<link
|
|
71
|
+
rel="stylesheet"
|
|
72
|
+
href="{{ url_for('static', path='/vendor/bootstrap-xlwings/dist/bootstrap-xlwings.min.css') }}" />
|
|
73
|
+
<script src="{{ url_for('static', path='/vendor/bootstrap/dist/js/bootstrap.bundle.min.js') }}"></script>
|
|
74
|
+
<script src="{{ url_for('static', path='/js/core/bootstrap-customizations.js') }}" defer></script>
|
|
75
|
+
{% endif %}
|
|
76
|
+
{# Axios #}
|
|
77
|
+
<script src="{{ url_for('static', path='/vendor/axios/dist/axios.min.js') }}" defer></script>
|
|
78
|
+
{# Examples #}
|
|
79
|
+
{% if settings.enable_examples %}
|
|
80
|
+
<script src="{{ url_for('static', path='/js/core/examples.js') }}" defer></script>
|
|
81
|
+
{% endif %}
|
|
82
|
+
{# Own #}
|
|
83
|
+
<link rel="stylesheet" href="{{ url_for('static', path='/css/core.css') }}" />
|
|
84
|
+
<link rel="stylesheet" href="{{ url_for('static', path='/css/style.css') }}" />
|
|
85
|
+
<script type="module" src="{{ url_for('static', path='/js/main.js') }}" defer></script>
|
|
86
|
+
<script src="{{ url_for('static', path='/js/ribbon.js') }}" defer></script>
|
|
87
|
+
{% block hotreload %}
|
|
88
|
+
{% if settings.environment == "dev" and settings.enable_socketio %}
|
|
89
|
+
<script src="{{ url_for('static', path='/js/core/hotreload.js') }}" defer></script>
|
|
90
|
+
{% endif %}
|
|
91
|
+
{% endblock hotreload %}
|
|
92
|
+
{% block extra_head %}
|
|
93
|
+
{# This allows to selectively load Alpine.js components #}
|
|
94
|
+
{% endblock extra_head %}
|
|
95
|
+
{# Alpine.js CSP build (must come after alpinejs-csp-boilerplate.js and custom code such as main.js) #}
|
|
96
|
+
{% if settings.enable_alpinejs_csp %}
|
|
97
|
+
<script src="{{ url_for('static', path='/vendor/@alpinejs/csp/dist/cdn.min.js') }}" defer></script>
|
|
98
|
+
{% endif %}
|
|
99
|
+
{% endblock head %}
|
|
100
|
+
</head>
|
|
101
|
+
|
|
102
|
+
<body hx-ext="head-support">
|
|
103
|
+
<div
|
|
104
|
+
id="global-error-alert"
|
|
105
|
+
class="alert alert-danger alert-dismissible fade show d-none z-index-1000"
|
|
106
|
+
role="alert">
|
|
107
|
+
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
|
108
|
+
<span></span>
|
|
109
|
+
</div>
|
|
110
|
+
<div id="global-status-alert" class="alert alert-warning alert-dismissible fade show d-none" role="alert">
|
|
111
|
+
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
|
112
|
+
<span></span>
|
|
113
|
+
</div>
|
|
114
|
+
{% block content %}
|
|
115
|
+
{% endblock content %}
|
|
116
|
+
</body>
|
|
117
|
+
</html>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Alpine.js sample
|
|
2
|
+
|
|
3
|
+
This example demonstrates a few common Alpine.js features. They are explained on the task pane itself.
|
|
4
|
+
|
|
5
|
+
To try it out, replace `app/routers/taskpane.py` with the following code:
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
from fastapi import APIRouter, Request
|
|
9
|
+
|
|
10
|
+
from ..config import settings
|
|
11
|
+
from ..templates import TemplateResponse
|
|
12
|
+
|
|
13
|
+
router = APIRouter(prefix=settings.app_path)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@router.get("/taskpane.html")
|
|
17
|
+
async def taskpane(request: Request):
|
|
18
|
+
return TemplateResponse(
|
|
19
|
+
request=request,
|
|
20
|
+
name="examples/alpine/taskpane.html",
|
|
21
|
+
)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
This sample also depends on:
|
|
25
|
+
|
|
26
|
+
- `app/static/js/core/examples.js`
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{% extends "base.html" %}
|
|
2
|
+
|
|
3
|
+
{% block content %}
|
|
4
|
+
<div class="container-fluid ps-3">
|
|
5
|
+
<h1 class="mt-4">1. Visibility</h1>
|
|
6
|
+
<p>Show and hide an element.</p>
|
|
7
|
+
<div x-data="visibility">
|
|
8
|
+
<button @click="toggle" class="btn btn-primary w-25" x-text="label"></button>
|
|
9
|
+
<span class="ms-4" x-show="isOpen">The Magic of Alpine.js!</span>
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
<h1 class="mt-4">2. Slider</h1>
|
|
13
|
+
<p>You can change the values either on the slider or as number and the other control will move in sync.</p>
|
|
14
|
+
<div x-data="slider" class="mt-4 mb-4">
|
|
15
|
+
<input type="range" min="0" max="100" class="form-range" :value="percentage" @input="update" />
|
|
16
|
+
<input type="number" min="0" max="100" class="form-control mt-2" :value="percentage" @input="update" />
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<h1>3. Names</h1>
|
|
20
|
+
<p>
|
|
21
|
+
Concatenates the first and last name as you type. You can activate the First Name input box via the
|
|
22
|
+
<code>/</code> keyboard shortcut.
|
|
23
|
+
</p>
|
|
24
|
+
<div x-data="nameForm">
|
|
25
|
+
<form>
|
|
26
|
+
<div class="mb-3">
|
|
27
|
+
<label for="firstName" class="form-label">First Name</label>
|
|
28
|
+
<input
|
|
29
|
+
name="firstName"
|
|
30
|
+
type="text"
|
|
31
|
+
class="form-control"
|
|
32
|
+
@input="handleInput"
|
|
33
|
+
@keydown.window.slash.prevent="focus"
|
|
34
|
+
autocorrect="off" />
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
<div class="mb-3">
|
|
38
|
+
<label for="lastName" class="form-label">Last Name</label>
|
|
39
|
+
<input name="lastName" type="text" class="form-control" @input="handleInput" autocorrect="off" />
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<p>Full Name</p>
|
|
43
|
+
<p x-text="fullName"></p>
|
|
44
|
+
</form>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
{% endblock content %}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Task pane authentication with htmx
|
|
2
|
+
|
|
3
|
+
- The task pane landing page has to be publicly accessible.
|
|
4
|
+
- Everything else can be locked down using the `dep.User` dependency.
|
|
5
|
+
- Since it is htmx that provides the `Authorization` header with every request, you'll end up with an authentication error if you use `hx-push-url="true"` or `hx-boost="true"` when right-clicking on the task pane and selecting `Reload`. This happens also with hot-reloading during development. The reason is that a full page reload isn't handled by htmx, which means that the Authorization header is missing. Therefore, the example doesn't push the url: you won't see any authentication errors when reloading, but in return, a reload always brings you back to the landing page.
|
|
6
|
+
|
|
7
|
+
To try it out, replace `app/routers/taskpane.py` with the following code:
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
from fastapi import APIRouter, Request
|
|
11
|
+
|
|
12
|
+
from .. import dependencies as dep
|
|
13
|
+
from ..config import settings
|
|
14
|
+
from ..templates import TemplateResponse
|
|
15
|
+
|
|
16
|
+
router = APIRouter(prefix=settings.app_path)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@router.get("/taskpane.html")
|
|
20
|
+
async def taskpane(request: Request):
|
|
21
|
+
return TemplateResponse(
|
|
22
|
+
request=request,
|
|
23
|
+
name="examples/auth/public.html",
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@router.get("/taskpane/protected")
|
|
28
|
+
async def taskpane_protected(request: Request, current_user: dep.User):
|
|
29
|
+
return TemplateResponse(
|
|
30
|
+
request=request,
|
|
31
|
+
name="examples/auth/protected.html",
|
|
32
|
+
context={"current_user": current_user},
|
|
33
|
+
)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
This sample also depends on:
|
|
37
|
+
|
|
38
|
+
- `app/static/js/htmx-handlers.js`
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{# manifest.xml requires the landing page to be public. Once loaded, htmx loads the protected endpoint.
|
|
2
|
+
hx-trigger requires a delay as otherwise it's fired before the rest of the htmx attributes are loaded. #}
|
|
3
|
+
{% extends "base.html" %}
|
|
4
|
+
|
|
5
|
+
{% block content %}
|
|
6
|
+
<div class="container-fluid pt-3 ps-3">
|
|
7
|
+
<a id="btn-protected" hx-get="{{ url_for('taskpane_protected') }}" hx-target="body" hx-trigger="load delay:1ms"
|
|
8
|
+
>Loading...</a
|
|
9
|
+
>
|
|
10
|
+
</div>
|
|
11
|
+
{% endblock content %}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Manipulating the Excel Object Model from the Task Pane
|
|
2
|
+
|
|
3
|
+
This example demonstrates how to manipulate Excel using htmx. You can enter a name in the text box and after clicking the button, it will add it to the bottom of column A in the active sheet.
|
|
4
|
+
|
|
5
|
+
To try it out, replace `app/routers/taskpane.py` with the following code:
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
from fastapi import APIRouter, Form, Request
|
|
9
|
+
|
|
10
|
+
from .. import dependencies as dep
|
|
11
|
+
from ..templates import TemplateResponse
|
|
12
|
+
|
|
13
|
+
router = APIRouter()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@router.get("/taskpane.html")
|
|
17
|
+
async def taskpane(request: Request):
|
|
18
|
+
return TemplateResponse(
|
|
19
|
+
request=request,
|
|
20
|
+
name="examples/excel_object_model/add_name_form.html",
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@router.post("/name")
|
|
25
|
+
async def name(request: Request, book: dep.Book, name: str = Form(None)):
|
|
26
|
+
# Error handling
|
|
27
|
+
error = "Please provide a name!" if name == "" else None
|
|
28
|
+
|
|
29
|
+
# Excel manipulations
|
|
30
|
+
sheet = book.sheets.active
|
|
31
|
+
row_ix = sheet["A1"].end("down").row if sheet["A1"].value else 0
|
|
32
|
+
book.sheets.active[row_ix, 0].value = name
|
|
33
|
+
|
|
34
|
+
# Include your book object as "book" in the context
|
|
35
|
+
return TemplateResponse(
|
|
36
|
+
request=request,
|
|
37
|
+
name="examples/excel_object_model/add_name_form.html",
|
|
38
|
+
context={
|
|
39
|
+
"error": error,
|
|
40
|
+
"book": book,
|
|
41
|
+
},
|
|
42
|
+
block_names="content",
|
|
43
|
+
)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
This sample also depends on:
|
|
47
|
+
|
|
48
|
+
- `static/js/core/htmx-handlers.js`
|
|
49
|
+
- `templates/_book.html`
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{% extends "base.html" %}
|
|
2
|
+
|
|
3
|
+
{% block content %}
|
|
4
|
+
<div class="container-fluid pt-3 ps-3" hx-target="this">
|
|
5
|
+
{% include "_book.html" %}
|
|
6
|
+
<form>
|
|
7
|
+
<div class="mb-3">
|
|
8
|
+
<label for="inputName" class="form-label">Name</label>
|
|
9
|
+
<input class="form-control" name="name" id="inputName" autocorrect="off" />
|
|
10
|
+
</div>
|
|
11
|
+
<button
|
|
12
|
+
type="submit"
|
|
13
|
+
class="btn btn-primary ps-4 pe-1"
|
|
14
|
+
xw-book="true"
|
|
15
|
+
xw-config='{"exclude": "MySheet"}'
|
|
16
|
+
hx-post="{{ url_for('name') }}"
|
|
17
|
+
hx-swap="outerHTML"
|
|
18
|
+
hx-disabled-elt="this">
|
|
19
|
+
Add Name to Excel
|
|
20
|
+
<span class="spinner-border spinner-border-sm htmx-indicator" role="status" aria-hidden="true"></span>
|
|
21
|
+
</button>
|
|
22
|
+
</form>
|
|
23
|
+
{% if error %}
|
|
24
|
+
<div class="alert alert-danger mt-4" role="alert">{{ error }}</div>
|
|
25
|
+
{% endif %}
|
|
26
|
+
</div>
|
|
27
|
+
{% endblock content %}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Hello World
|
|
2
|
+
|
|
3
|
+
This example alternately prints `Hello xlwings!` and `Bye xlwings!` in cell A1 of the first sheet whenever you click the button on the task pane.
|
|
4
|
+
|
|
5
|
+
It is the default example in `app/routers/taskpane.py`.
|
|
6
|
+
|
|
7
|
+
The sample also depends on:
|
|
8
|
+
|
|
9
|
+
- `app/custom_scripts/examples.py`
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{% extends "base.html" %}
|
|
2
|
+
|
|
3
|
+
{% block content %}
|
|
4
|
+
<div class="container-fluid pt-3 ps-3">
|
|
5
|
+
<h1>Example Task Pane</h1>
|
|
6
|
+
<div class="mb-3 d-flex flex-column gap-2">
|
|
7
|
+
<button xw-click="hello_world" class="btn btn-primary btn-sm" type="button">
|
|
8
|
+
Write 'Hello/Bye xlwings!' to A1
|
|
9
|
+
</button>
|
|
10
|
+
<button
|
|
11
|
+
xw-click="setup_custom_functions"
|
|
12
|
+
xw-config='{"exclude": "MySheet"}'
|
|
13
|
+
class="btn btn-primary btn-sm"
|
|
14
|
+
type="button">
|
|
15
|
+
Insert sheet with custom functions
|
|
16
|
+
</button>
|
|
17
|
+
{% if not settings.enable_wasm %}
|
|
18
|
+
<button xw-click="show_alert" class="btn btn-primary btn-sm" type="button">Show an alert</button>
|
|
19
|
+
{% endif %}
|
|
20
|
+
<button xw-click="show_plot" class="btn btn-primary btn-sm" type="button">Insert a Matplotlib Plot</button>
|
|
21
|
+
<button xw-click="show_error" class="btn btn-primary btn-sm" type="button">Show an error message</button>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
{% endblock content %}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# htmx form sample
|
|
2
|
+
|
|
3
|
+
This example uses a Bootstrap form, adopted from:
|
|
4
|
+
https://getbootstrap.com/docs/5.3/forms/overview/#overview
|
|
5
|
+
|
|
6
|
+
- It sends the content of the input field (requires a "name" tag) to the backend using [htmx](https://htmx.org/)
|
|
7
|
+
- On the backend, it calls a custom function and
|
|
8
|
+
- returns the result via the `_greeting.html` template. The leading underscore means that it is a partial HTML snippet, not a full page.
|
|
9
|
+
- Back on the frontend, htmx takes care of displaying that HTML snippet in the `#result` div via `hx-target` tag.
|
|
10
|
+
|
|
11
|
+
To try it out, replace `app/routers/taskpane.py` with the following code:
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from fastapi import APIRouter, Form, Request
|
|
15
|
+
|
|
16
|
+
from .. import custom_functions
|
|
17
|
+
from ..config import settings
|
|
18
|
+
from ..templates import TemplateResponse
|
|
19
|
+
|
|
20
|
+
router = APIRouter(prefix=settings.app_path)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@router.get("/taskpane.html")
|
|
24
|
+
async def taskpane(request: Request):
|
|
25
|
+
return TemplateResponse(
|
|
26
|
+
request=request,
|
|
27
|
+
name="examples/htmx_form/taskpane_htmx_form.html",
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@router.post("/hello")
|
|
32
|
+
async def hello(request: Request, fullname: str = Form()):
|
|
33
|
+
error = "Please provide a name!" if not fullname else None
|
|
34
|
+
greeting = custom_functions.hello(fullname)
|
|
35
|
+
return TemplateResponse(
|
|
36
|
+
request=request,
|
|
37
|
+
name="examples/htmx_form/_greeting.html",
|
|
38
|
+
context={"greeting": greeting, "error": error},
|
|
39
|
+
)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
This sample also depends on:
|
|
43
|
+
|
|
44
|
+
- no dependencies
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{% extends "base.html" %}
|
|
2
|
+
|
|
3
|
+
{% block content %}
|
|
4
|
+
<div class="container-fluid pt-3 ps-3">
|
|
5
|
+
<form>
|
|
6
|
+
<div class="mb-3">
|
|
7
|
+
<label for="inputName" class="form-label">Name</label>
|
|
8
|
+
<input class="form-control" name="fullname" id="inputName" autocorrect="off" />
|
|
9
|
+
</div>
|
|
10
|
+
<button
|
|
11
|
+
type="submit"
|
|
12
|
+
class="btn btn-primary ps-4 pe-1"
|
|
13
|
+
hx-post="{{ url_for('hello') }}"
|
|
14
|
+
hx-target="#result"
|
|
15
|
+
hx-disabled-elt="this">
|
|
16
|
+
Submit <span class="spinner-border spinner-border-sm htmx-indicator" role="status" aria-hidden="true"></span>
|
|
17
|
+
</button>
|
|
18
|
+
</form>
|
|
19
|
+
<div id="result" class="mt-4"></div>
|
|
20
|
+
</div>
|
|
21
|
+
{% endblock content %}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Live Form Validation
|
|
2
|
+
|
|
3
|
+
This example demonstrates how to validate a form input live on the backend via htmx. If you provide a name that has less than 4 characters, you'll get a validation error shown.
|
|
4
|
+
|
|
5
|
+
To try it out, replace `app/routers/taskpane.py` with the following code:
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
from fastapi import APIRouter, Form, Request, status
|
|
9
|
+
from fastapi.responses import PlainTextResponse, Response
|
|
10
|
+
|
|
11
|
+
from .. import dependencies as dep
|
|
12
|
+
from ..templates import TemplateResponse
|
|
13
|
+
|
|
14
|
+
router = APIRouter()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@router.get("/taskpane.html")
|
|
18
|
+
async def taskpane(request: Request):
|
|
19
|
+
return TemplateResponse(
|
|
20
|
+
request=request,
|
|
21
|
+
name="examples/live_form_validation/add_name_form.html",
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def validate_name(name: str):
|
|
26
|
+
if 0 < len(name) < 4:
|
|
27
|
+
return "Name must have at least 4 characters!"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@router.post("/name")
|
|
31
|
+
async def name(request: Request, book: dep.Book, name: str = Form(None)):
|
|
32
|
+
# Validation
|
|
33
|
+
error = validate_name(name)
|
|
34
|
+
if error:
|
|
35
|
+
return Response(status_code=status.HTTP_204_NO_CONTENT)
|
|
36
|
+
|
|
37
|
+
# Excel manipulations
|
|
38
|
+
sheet = book.sheets.active
|
|
39
|
+
row_ix = sheet["A1"].end("down").row if sheet["A1"].value else 0
|
|
40
|
+
book.sheets.active[row_ix, 0].value = name
|
|
41
|
+
|
|
42
|
+
# Include your book object as "book" in the context
|
|
43
|
+
return TemplateResponse(
|
|
44
|
+
request=request,
|
|
45
|
+
name="examples/live_form_validation/add_name_form.html",
|
|
46
|
+
context={"book": book},
|
|
47
|
+
block_names="content",
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@router.get("/name/validation")
|
|
52
|
+
async def validate_name_input(request: Request, name: str):
|
|
53
|
+
error = validate_name(name)
|
|
54
|
+
return PlainTextResponse(error if error else " ")
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
This sample also depends on:
|
|
58
|
+
|
|
59
|
+
- `static/js/core/htmx-handlers.js`
|
|
60
|
+
- `templates/_book.html`
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{% extends "base.html" %}
|
|
2
|
+
|
|
3
|
+
{% block content %}
|
|
4
|
+
<div class="container-fluid pt-3 ps-3" id="mycontainer">
|
|
5
|
+
{% include "_book.html" %}
|
|
6
|
+
<form>
|
|
7
|
+
<div class="mb-3">
|
|
8
|
+
<label for="inputName" class="form-label">Name</label>
|
|
9
|
+
<input
|
|
10
|
+
class="form-control"
|
|
11
|
+
name="name"
|
|
12
|
+
id="inputName"
|
|
13
|
+
autocorrect="off"
|
|
14
|
+
hx-get="{{ url_for('validate_name_input') }}"
|
|
15
|
+
hx-target="next .invalid-feedback"
|
|
16
|
+
hx-trigger="keyup delay:300ms changed" />
|
|
17
|
+
<div class="invalid-feedback d-block"> </div>
|
|
18
|
+
</div>
|
|
19
|
+
<button
|
|
20
|
+
type="submit"
|
|
21
|
+
class="btn btn-primary ps-4 pe-1"
|
|
22
|
+
xw-book="true"
|
|
23
|
+
xw-config='{"exclude": "MySheet"}'
|
|
24
|
+
hx-post="{{ url_for('name') }}"
|
|
25
|
+
hx-swap="outerHTML"
|
|
26
|
+
hx-target="#mycontainer"
|
|
27
|
+
hx-disabled-elt="this">
|
|
28
|
+
Add Name to Excel
|
|
29
|
+
<span class="spinner-border spinner-border-sm htmx-indicator" role="status" aria-hidden="true"></span>
|
|
30
|
+
</button>
|
|
31
|
+
</form>
|
|
32
|
+
</div>
|
|
33
|
+
{% endblock content %}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Multiple Apps
|
|
2
|
+
|
|
3
|
+
This example loads a different task pane depending on the name of the workbook.
|
|
4
|
+
|
|
5
|
+
To try it out, replace `app/routers/taskpane.py` with the following code:
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
from fastapi import APIRouter, Request
|
|
9
|
+
|
|
10
|
+
from ..config import settings
|
|
11
|
+
from ..templates import TemplateResponse
|
|
12
|
+
|
|
13
|
+
router = APIRouter(prefix=settings.app_path)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@router.get("/taskpane")
|
|
17
|
+
@router.get("/taskpane.html")
|
|
18
|
+
async def taskpane(request: Request, app: str = None):
|
|
19
|
+
if not app:
|
|
20
|
+
template = "examples/multi_app/taskpane_loader.html"
|
|
21
|
+
elif app == "1":
|
|
22
|
+
template = "examples/multi_app/taskpane1.html"
|
|
23
|
+
elif app == "2":
|
|
24
|
+
template = "examples/multi_app/taskpane2.html"
|
|
25
|
+
|
|
26
|
+
return TemplateResponse(
|
|
27
|
+
request=request,
|
|
28
|
+
name=template,
|
|
29
|
+
)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The sample also depends on:
|
|
33
|
+
|
|
34
|
+
- `app/static/js/core/examples.js`
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Navigation via htmx and Bootstrap
|
|
2
|
+
|
|
3
|
+
This sample uses a Bootstrap nav (see https://getbootstrap.com/docs/5.3/components/navs-tabs/#underline) to navigate between 3 different pages, but using only a single taskpane. It makes use of the htmx tag `hx-boost`, which converts traditional anchor tags into partial page loads.
|
|
4
|
+
|
|
5
|
+
To try it out, replace `app/routers/taskpane.py` with the following code:
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
from fastapi import APIRouter, Request
|
|
9
|
+
|
|
10
|
+
from ..config import settings
|
|
11
|
+
from ..templates import TemplateResponse
|
|
12
|
+
|
|
13
|
+
router = APIRouter(prefix=settings.app_path)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@router.get("/taskpane.html")
|
|
17
|
+
@router.get("/taskpane/{page}")
|
|
18
|
+
async def taskpane(request: Request, page: str = "one"):
|
|
19
|
+
return TemplateResponse(
|
|
20
|
+
request=request,
|
|
21
|
+
name=f"examples/navigation/taskpane_{page}.html",
|
|
22
|
+
context={"page": page},
|
|
23
|
+
)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
This sample also depends on:
|
|
27
|
+
|
|
28
|
+
- no dependencies
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<ul class="nav nav-underline pb-4" hx-boost="true">
|
|
2
|
+
{%
|
|
3
|
+
set pages = [
|
|
4
|
+
('One', url_for('taskpane', page='one')),
|
|
5
|
+
('Two', url_for('taskpane', page='two')),
|
|
6
|
+
('Three', url_for('taskpane', page='three'))
|
|
7
|
+
]
|
|
8
|
+
%}
|
|
9
|
+
{% for name, url in pages %}
|
|
10
|
+
<li class="nav-item">
|
|
11
|
+
<a class="nav-link {% if page == name|lower %}active{% endif %}" aria-current="page" href="{{ url }}"
|
|
12
|
+
>{{ name }}</a
|
|
13
|
+
>
|
|
14
|
+
</li>
|
|
15
|
+
{% endfor %}
|
|
16
|
+
</ul>
|