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.
Files changed (313) hide show
  1. xlwings_server/.env.template +145 -0
  2. xlwings_server/__init__.py +12 -0
  3. xlwings_server/_version.py +34 -0
  4. xlwings_server/auth/__init__.py +0 -0
  5. xlwings_server/auth/custom/__init__.py +26 -0
  6. xlwings_server/auth/entraid/__init__.py +131 -0
  7. xlwings_server/auth/entraid/jwks.py +10 -0
  8. xlwings_server/azure_functions_templates/.funcignore +28 -0
  9. xlwings_server/azure_functions_templates/function_app.py +28 -0
  10. xlwings_server/azure_functions_templates/host.json +22 -0
  11. xlwings_server/azure_functions_templates/local.settings.json +8 -0
  12. xlwings_server/build_utils/__init__.py +9 -0
  13. xlwings_server/build_utils/static_file_hasher.py +212 -0
  14. xlwings_server/cli.py +1592 -0
  15. xlwings_server/config.py +228 -0
  16. xlwings_server/custom_functions/__init__.py +8 -0
  17. xlwings_server/custom_functions/examples.py +177 -0
  18. xlwings_server/custom_scripts/__init__.py +8 -0
  19. xlwings_server/custom_scripts/examples.py +94 -0
  20. xlwings_server/databases.py +19 -0
  21. xlwings_server/dependencies.py +126 -0
  22. xlwings_server/docker_templates/.dockerignore +15 -0
  23. xlwings_server/docker_templates/Dockerfile +60 -0
  24. xlwings_server/docker_templates/docker-compose.yaml +32 -0
  25. xlwings_server/hotreload.py +59 -0
  26. xlwings_server/main.py +242 -0
  27. xlwings_server/models/__init__.py +14 -0
  28. xlwings_server/models/user.py +53 -0
  29. xlwings_server/object_handles.py +142 -0
  30. xlwings_server/routers/__init__.py +0 -0
  31. xlwings_server/routers/manifest.py +82 -0
  32. xlwings_server/routers/root.py +16 -0
  33. xlwings_server/routers/socketio.py +69 -0
  34. xlwings_server/routers/taskpane.py +12 -0
  35. xlwings_server/routers/xlwings.py +197 -0
  36. xlwings_server/security_headers.json +53 -0
  37. xlwings_server/serializers/__init__.py +25 -0
  38. xlwings_server/serializers/default_serializer.py +19 -0
  39. xlwings_server/serializers/dictionary_serializer.py +25 -0
  40. xlwings_server/serializers/framework.py +50 -0
  41. xlwings_server/serializers/numpy_serializer.py +26 -0
  42. xlwings_server/serializers/pandas_serializer.py +95 -0
  43. xlwings_server/static/css/core.css +28 -0
  44. xlwings_server/static/css/style.css +0 -0
  45. xlwings_server/static/images/favicon.png +0 -0
  46. xlwings_server/static/images/xlwings-16.png +0 -0
  47. xlwings_server/static/images/xlwings-32.png +0 -0
  48. xlwings_server/static/images/xlwings-64.png +0 -0
  49. xlwings_server/static/images/xlwings-80.png +0 -0
  50. xlwings_server/static/js/auth.js +13 -0
  51. xlwings_server/static/js/config.js +4 -0
  52. xlwings_server/static/js/core/alpinejs-csp-boilerplate.js +11 -0
  53. xlwings_server/static/js/core/bootstrap-customizations.js +7 -0
  54. xlwings_server/static/js/core/custom-functions-code.js +296 -0
  55. xlwings_server/static/js/core/examples.js +62 -0
  56. xlwings_server/static/js/core/hotreload.js +3 -0
  57. xlwings_server/static/js/core/htmx-handlers.js +86 -0
  58. xlwings_server/static/js/core/officejs-history-fix-part1.js +3 -0
  59. xlwings_server/static/js/core/officejs-history-fix-part2.js +2 -0
  60. xlwings_server/static/js/core/reload-custom-functions.js +79 -0
  61. xlwings_server/static/js/core/socketio-handlers.js +34 -0
  62. xlwings_server/static/js/core/xlwings-alert.js +22 -0
  63. xlwings_server/static/js/core/xlwingsjs/alert.js +85 -0
  64. xlwings_server/static/js/core/xlwingsjs/auth.js +63 -0
  65. xlwings_server/static/js/core/xlwingsjs/sheet-buttons.js +133 -0
  66. xlwings_server/static/js/core/xlwingsjs/utils.js +119 -0
  67. xlwings_server/static/js/core/xlwingsjs/wasm.js +131 -0
  68. xlwings_server/static/js/core/xlwingsjs/xlwings.js +1060 -0
  69. xlwings_server/static/js/main.js +0 -0
  70. xlwings_server/static/js/ribbon.js +17 -0
  71. xlwings_server/static/vendor/@alpinejs/LICENSE +21 -0
  72. xlwings_server/static/vendor/@alpinejs/csp/dist/cdn.min.js +7 -0
  73. xlwings_server/static/vendor/@microsoft/office-js/LICENSE.md +76 -0
  74. xlwings_server/static/vendor/@microsoft/office-js/dist/af-za/office_strings.js +8 -0
  75. xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/agaveerrorux.js +18 -0
  76. xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/images/agavedefaulticon32x32.png +0 -0
  77. xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/images/agavedefaulticon96x96.png +0 -0
  78. xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/images/businessbarclose_16x16x32.png +0 -0
  79. xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/images/dropdownarrow_16x16x32.png +0 -0
  80. xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/images/ellipsis_16x16x32.png +0 -0
  81. xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/images/miniinfoblue_16x16x32.png +0 -0
  82. xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/images/moe_default_icon.png +0 -0
  83. xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/images/moe_status_icons.png +0 -0
  84. xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/images/office.png +0 -0
  85. xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/images/refresh_16x16x32.png +0 -0
  86. xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/index.html +16 -0
  87. xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/style/agaveerrorux.css +482 -0
  88. xlwings_server/static/vendor/@microsoft/office-js/dist/am-et/office_strings.js +1 -0
  89. xlwings_server/static/vendor/@microsoft/office-js/dist/ar-ae/office_strings.js +8 -0
  90. xlwings_server/static/vendor/@microsoft/office-js/dist/ar-bh/office_strings.js +8 -0
  91. xlwings_server/static/vendor/@microsoft/office-js/dist/ar-dz/office_strings.js +8 -0
  92. xlwings_server/static/vendor/@microsoft/office-js/dist/ar-eg/office_strings.js +8 -0
  93. xlwings_server/static/vendor/@microsoft/office-js/dist/ar-iq/office_strings.js +8 -0
  94. xlwings_server/static/vendor/@microsoft/office-js/dist/ar-jo/office_strings.js +8 -0
  95. xlwings_server/static/vendor/@microsoft/office-js/dist/ar-kw/office_strings.js +8 -0
  96. xlwings_server/static/vendor/@microsoft/office-js/dist/ar-lb/office_strings.js +8 -0
  97. xlwings_server/static/vendor/@microsoft/office-js/dist/ar-ly/office_strings.js +8 -0
  98. xlwings_server/static/vendor/@microsoft/office-js/dist/ar-ma/office_strings.js +8 -0
  99. xlwings_server/static/vendor/@microsoft/office-js/dist/ar-om/office_strings.js +8 -0
  100. xlwings_server/static/vendor/@microsoft/office-js/dist/ar-qa/office_strings.js +8 -0
  101. xlwings_server/static/vendor/@microsoft/office-js/dist/ar-sa/office_strings.js +1 -0
  102. xlwings_server/static/vendor/@microsoft/office-js/dist/ar-sy/office_strings.js +8 -0
  103. xlwings_server/static/vendor/@microsoft/office-js/dist/ar-tn/office_strings.js +8 -0
  104. xlwings_server/static/vendor/@microsoft/office-js/dist/ar-ye/office_strings.js +8 -0
  105. xlwings_server/static/vendor/@microsoft/office-js/dist/ariatelemetry/aria-web-telemetry-2.8.0.min.js +2 -0
  106. xlwings_server/static/vendor/@microsoft/office-js/dist/ariatelemetry/aria-web-telemetry-2.9.0.min.js +2 -0
  107. xlwings_server/static/vendor/@microsoft/office-js/dist/ariatelemetry/aria-web-telemetry.js +1 -0
  108. xlwings_server/static/vendor/@microsoft/office-js/dist/az-latn-az/office_strings.js +8 -0
  109. xlwings_server/static/vendor/@microsoft/office-js/dist/be-by/office_strings.js +8 -0
  110. xlwings_server/static/vendor/@microsoft/office-js/dist/bg-bg/office_strings.js +1 -0
  111. xlwings_server/static/vendor/@microsoft/office-js/dist/bn-in/office_strings.js +1 -0
  112. xlwings_server/static/vendor/@microsoft/office-js/dist/bs-latn-ba/office_strings.js +8 -0
  113. xlwings_server/static/vendor/@microsoft/office-js/dist/ca-es/office_strings.js +1 -0
  114. xlwings_server/static/vendor/@microsoft/office-js/dist/cs-cz/office_strings.js +1 -0
  115. xlwings_server/static/vendor/@microsoft/office-js/dist/cy-gb/office_strings.js +1 -0
  116. xlwings_server/static/vendor/@microsoft/office-js/dist/da-dk/office_strings.js +1 -0
  117. xlwings_server/static/vendor/@microsoft/office-js/dist/de-at/office_strings.js +8 -0
  118. xlwings_server/static/vendor/@microsoft/office-js/dist/de-ch/office_strings.js +8 -0
  119. xlwings_server/static/vendor/@microsoft/office-js/dist/de-de/office_strings.js +1 -0
  120. xlwings_server/static/vendor/@microsoft/office-js/dist/de-li/office_strings.js +8 -0
  121. xlwings_server/static/vendor/@microsoft/office-js/dist/de-lu/office_strings.js +8 -0
  122. xlwings_server/static/vendor/@microsoft/office-js/dist/el-gr/office_strings.js +1 -0
  123. xlwings_server/static/vendor/@microsoft/office-js/dist/en-029/office_strings.js +8 -0
  124. xlwings_server/static/vendor/@microsoft/office-js/dist/en-au/office_strings.js +8 -0
  125. xlwings_server/static/vendor/@microsoft/office-js/dist/en-bz/office_strings.js +8 -0
  126. xlwings_server/static/vendor/@microsoft/office-js/dist/en-ca/office_strings.js +8 -0
  127. xlwings_server/static/vendor/@microsoft/office-js/dist/en-gb/office_strings.js +8 -0
  128. xlwings_server/static/vendor/@microsoft/office-js/dist/en-ie/office_strings.js +8 -0
  129. xlwings_server/static/vendor/@microsoft/office-js/dist/en-in/office_strings.js +8 -0
  130. xlwings_server/static/vendor/@microsoft/office-js/dist/en-jm/office_strings.js +8 -0
  131. xlwings_server/static/vendor/@microsoft/office-js/dist/en-my/office_strings.js +8 -0
  132. xlwings_server/static/vendor/@microsoft/office-js/dist/en-nz/office_strings.js +8 -0
  133. xlwings_server/static/vendor/@microsoft/office-js/dist/en-ph/office_strings.js +8 -0
  134. xlwings_server/static/vendor/@microsoft/office-js/dist/en-sg/office_strings.js +8 -0
  135. xlwings_server/static/vendor/@microsoft/office-js/dist/en-tt/office_strings.js +8 -0
  136. xlwings_server/static/vendor/@microsoft/office-js/dist/en-us/office_strings.js +8 -0
  137. xlwings_server/static/vendor/@microsoft/office-js/dist/en-za/office_strings.js +8 -0
  138. xlwings_server/static/vendor/@microsoft/office-js/dist/en-zw/office_strings.js +8 -0
  139. xlwings_server/static/vendor/@microsoft/office-js/dist/es-ar/office_strings.js +8 -0
  140. xlwings_server/static/vendor/@microsoft/office-js/dist/es-bo/office_strings.js +8 -0
  141. xlwings_server/static/vendor/@microsoft/office-js/dist/es-cl/office_strings.js +8 -0
  142. xlwings_server/static/vendor/@microsoft/office-js/dist/es-co/office_strings.js +8 -0
  143. xlwings_server/static/vendor/@microsoft/office-js/dist/es-cr/office_strings.js +8 -0
  144. xlwings_server/static/vendor/@microsoft/office-js/dist/es-do/office_strings.js +8 -0
  145. xlwings_server/static/vendor/@microsoft/office-js/dist/es-ec/office_strings.js +8 -0
  146. xlwings_server/static/vendor/@microsoft/office-js/dist/es-es/office_strings.js +1 -0
  147. xlwings_server/static/vendor/@microsoft/office-js/dist/es-gt/office_strings.js +8 -0
  148. xlwings_server/static/vendor/@microsoft/office-js/dist/es-hn/office_strings.js +8 -0
  149. xlwings_server/static/vendor/@microsoft/office-js/dist/es-mx/office_strings.js +1 -0
  150. xlwings_server/static/vendor/@microsoft/office-js/dist/es-ni/office_strings.js +8 -0
  151. xlwings_server/static/vendor/@microsoft/office-js/dist/es-pa/office_strings.js +8 -0
  152. xlwings_server/static/vendor/@microsoft/office-js/dist/es-pe/office_strings.js +8 -0
  153. xlwings_server/static/vendor/@microsoft/office-js/dist/es-pr/office_strings.js +8 -0
  154. xlwings_server/static/vendor/@microsoft/office-js/dist/es-py/office_strings.js +8 -0
  155. xlwings_server/static/vendor/@microsoft/office-js/dist/es-sv/office_strings.js +8 -0
  156. xlwings_server/static/vendor/@microsoft/office-js/dist/es-us/office_strings.js +8 -0
  157. xlwings_server/static/vendor/@microsoft/office-js/dist/es-uy/office_strings.js +8 -0
  158. xlwings_server/static/vendor/@microsoft/office-js/dist/es-ve/office_strings.js +8 -0
  159. xlwings_server/static/vendor/@microsoft/office-js/dist/es6-promise.js +5 -0
  160. xlwings_server/static/vendor/@microsoft/office-js/dist/et-ee/office_strings.js +1 -0
  161. xlwings_server/static/vendor/@microsoft/office-js/dist/eu-es/office_strings.js +1 -0
  162. xlwings_server/static/vendor/@microsoft/office-js/dist/excel-15.01.js +11 -0
  163. xlwings_server/static/vendor/@microsoft/office-js/dist/excel-15.02.js +11 -0
  164. xlwings_server/static/vendor/@microsoft/office-js/dist/excel-15.js +11 -0
  165. xlwings_server/static/vendor/@microsoft/office-js/dist/excel-mac-16.00-core.js +11 -0
  166. xlwings_server/static/vendor/@microsoft/office-js/dist/excel-mac-16.00.js +25 -0
  167. xlwings_server/static/vendor/@microsoft/office-js/dist/excel-web-16.00-core.js +11 -0
  168. xlwings_server/static/vendor/@microsoft/office-js/dist/excel-web-16.00.js +25 -0
  169. xlwings_server/static/vendor/@microsoft/office-js/dist/excel-win32-16.00.js +19 -0
  170. xlwings_server/static/vendor/@microsoft/office-js/dist/excel-win32-16.01-core.js +11 -0
  171. xlwings_server/static/vendor/@microsoft/office-js/dist/excel-win32-16.01.js +25 -0
  172. xlwings_server/static/vendor/@microsoft/office-js/dist/excel-winrt-16.00.js +25 -0
  173. xlwings_server/static/vendor/@microsoft/office-js/dist/excelios-15.js +11 -0
  174. xlwings_server/static/vendor/@microsoft/office-js/dist/excelwebapp-15.01.js +11 -0
  175. xlwings_server/static/vendor/@microsoft/office-js/dist/excelwebapp-15.02.js +11 -0
  176. xlwings_server/static/vendor/@microsoft/office-js/dist/excelwebapp-15.js +11 -0
  177. xlwings_server/static/vendor/@microsoft/office-js/dist/fa-ir/office_strings.js +1 -0
  178. xlwings_server/static/vendor/@microsoft/office-js/dist/fi-fi/office_strings.js +1 -0
  179. xlwings_server/static/vendor/@microsoft/office-js/dist/fil-ph/office_strings.js +1 -0
  180. xlwings_server/static/vendor/@microsoft/office-js/dist/fr-be/office_strings.js +8 -0
  181. xlwings_server/static/vendor/@microsoft/office-js/dist/fr-ca/office_strings.js +1 -0
  182. xlwings_server/static/vendor/@microsoft/office-js/dist/fr-ch/office_strings.js +8 -0
  183. xlwings_server/static/vendor/@microsoft/office-js/dist/fr-fr/office_strings.js +1 -0
  184. xlwings_server/static/vendor/@microsoft/office-js/dist/fr-lu/office_strings.js +8 -0
  185. xlwings_server/static/vendor/@microsoft/office-js/dist/fr-mc/office_strings.js +8 -0
  186. xlwings_server/static/vendor/@microsoft/office-js/dist/ga-ie/office_strings.js +8 -0
  187. xlwings_server/static/vendor/@microsoft/office-js/dist/gl-es/office_strings.js +1 -0
  188. xlwings_server/static/vendor/@microsoft/office-js/dist/gu-in/office_strings.js +1 -0
  189. xlwings_server/static/vendor/@microsoft/office-js/dist/he-il/office_strings.js +1 -0
  190. xlwings_server/static/vendor/@microsoft/office-js/dist/hi-in/office_strings.js +1 -0
  191. xlwings_server/static/vendor/@microsoft/office-js/dist/hr-ba/office_strings.js +8 -0
  192. xlwings_server/static/vendor/@microsoft/office-js/dist/hr-hr/office_strings.js +1 -0
  193. xlwings_server/static/vendor/@microsoft/office-js/dist/html2canvas.js +8 -0
  194. xlwings_server/static/vendor/@microsoft/office-js/dist/hu-hu/office_strings.js +1 -0
  195. xlwings_server/static/vendor/@microsoft/office-js/dist/hy-am/office_strings.js +8 -0
  196. xlwings_server/static/vendor/@microsoft/office-js/dist/id-id/office_strings.js +1 -0
  197. xlwings_server/static/vendor/@microsoft/office-js/dist/is-is/office_strings.js +1 -0
  198. xlwings_server/static/vendor/@microsoft/office-js/dist/it-ch/office_strings.js +8 -0
  199. xlwings_server/static/vendor/@microsoft/office-js/dist/it-it/office_strings.js +1 -0
  200. xlwings_server/static/vendor/@microsoft/office-js/dist/ja-jp/office_strings.js +1 -0
  201. xlwings_server/static/vendor/@microsoft/office-js/dist/ka-ge/office_strings.js +8 -0
  202. xlwings_server/static/vendor/@microsoft/office-js/dist/kk-kz/office_strings.js +1 -0
  203. xlwings_server/static/vendor/@microsoft/office-js/dist/km-kh/office_strings.js +8 -0
  204. xlwings_server/static/vendor/@microsoft/office-js/dist/kn-in/office_strings.js +1 -0
  205. xlwings_server/static/vendor/@microsoft/office-js/dist/ko-kr/office_strings.js +1 -0
  206. xlwings_server/static/vendor/@microsoft/office-js/dist/lb-lu/office_strings.js +8 -0
  207. xlwings_server/static/vendor/@microsoft/office-js/dist/lo-la/office_strings.js +1 -0
  208. xlwings_server/static/vendor/@microsoft/office-js/dist/lt-lt/office_strings.js +1 -0
  209. xlwings_server/static/vendor/@microsoft/office-js/dist/lv-lv/office_strings.js +1 -0
  210. xlwings_server/static/vendor/@microsoft/office-js/dist/mk-mk/office_strings.js +8 -0
  211. xlwings_server/static/vendor/@microsoft/office-js/dist/ml-in/office_strings.js +1 -0
  212. xlwings_server/static/vendor/@microsoft/office-js/dist/mn-mn/office_strings.js +8 -0
  213. xlwings_server/static/vendor/@microsoft/office-js/dist/mr-in/office_strings.js +1 -0
  214. xlwings_server/static/vendor/@microsoft/office-js/dist/ms-bn/office_strings.js +8 -0
  215. xlwings_server/static/vendor/@microsoft/office-js/dist/ms-my/office_strings.js +1 -0
  216. xlwings_server/static/vendor/@microsoft/office-js/dist/mt-mt/office_strings.js +8 -0
  217. xlwings_server/static/vendor/@microsoft/office-js/dist/nb-no/office_strings.js +1 -0
  218. xlwings_server/static/vendor/@microsoft/office-js/dist/ne-np/office_strings.js +8 -0
  219. xlwings_server/static/vendor/@microsoft/office-js/dist/nl-be/office_strings.js +8 -0
  220. xlwings_server/static/vendor/@microsoft/office-js/dist/nl-nl/office_strings.js +1 -0
  221. xlwings_server/static/vendor/@microsoft/office-js/dist/nn-no/office_strings.js +1 -0
  222. xlwings_server/static/vendor/@microsoft/office-js/dist/o15apptofilemappingtable.js +11 -0
  223. xlwings_server/static/vendor/@microsoft/office-js/dist/office-vsdoc.js +28596 -0
  224. xlwings_server/static/vendor/@microsoft/office-js/dist/office.js +84 -0
  225. xlwings_server/static/vendor/@microsoft/office-js/dist/pl-pl/office_strings.js +1 -0
  226. xlwings_server/static/vendor/@microsoft/office-js/dist/pt-br/office_strings.js +1 -0
  227. xlwings_server/static/vendor/@microsoft/office-js/dist/pt-pt/office_strings.js +1 -0
  228. xlwings_server/static/vendor/@microsoft/office-js/dist/ro-ro/office_strings.js +1 -0
  229. xlwings_server/static/vendor/@microsoft/office-js/dist/ru-ru/office_strings.js +1 -0
  230. xlwings_server/static/vendor/@microsoft/office-js/dist/si-lk/office_strings.js +8 -0
  231. xlwings_server/static/vendor/@microsoft/office-js/dist/sk-sk/office_strings.js +1 -0
  232. xlwings_server/static/vendor/@microsoft/office-js/dist/sl-si/office_strings.js +1 -0
  233. xlwings_server/static/vendor/@microsoft/office-js/dist/sq-al/office_strings.js +8 -0
  234. xlwings_server/static/vendor/@microsoft/office-js/dist/sr-cyrl-cs/office_strings.js +1 -0
  235. xlwings_server/static/vendor/@microsoft/office-js/dist/sr-cyrl-rs/office_strings.js +1 -0
  236. xlwings_server/static/vendor/@microsoft/office-js/dist/sr-latn-cs/office_strings.js +1 -0
  237. xlwings_server/static/vendor/@microsoft/office-js/dist/sr-latn-rs/office_strings.js +1 -0
  238. xlwings_server/static/vendor/@microsoft/office-js/dist/sv-fi/office_strings.js +8 -0
  239. xlwings_server/static/vendor/@microsoft/office-js/dist/sv-se/office_strings.js +1 -0
  240. xlwings_server/static/vendor/@microsoft/office-js/dist/sw-ke/office_strings.js +1 -0
  241. xlwings_server/static/vendor/@microsoft/office-js/dist/ta-in/office_strings.js +1 -0
  242. xlwings_server/static/vendor/@microsoft/office-js/dist/te-in/office_strings.js +1 -0
  243. xlwings_server/static/vendor/@microsoft/office-js/dist/telemetry/oteljs.js +1 -0
  244. xlwings_server/static/vendor/@microsoft/office-js/dist/telemetry/oteljs_agave.js +1 -0
  245. xlwings_server/static/vendor/@microsoft/office-js/dist/th-th/office_strings.js +1 -0
  246. xlwings_server/static/vendor/@microsoft/office-js/dist/tr-tr/office_strings.js +1 -0
  247. xlwings_server/static/vendor/@microsoft/office-js/dist/uk-ua/office_strings.js +1 -0
  248. xlwings_server/static/vendor/@microsoft/office-js/dist/ur-pk/office_strings.js +1 -0
  249. xlwings_server/static/vendor/@microsoft/office-js/dist/vi-vn/office_strings.js +1 -0
  250. xlwings_server/static/vendor/@microsoft/office-js/dist/webauth/webauth.browserauth.js +77 -0
  251. xlwings_server/static/vendor/@microsoft/office-js/dist/webauth/webauth.implicit.js +35 -0
  252. xlwings_server/static/vendor/@microsoft/office-js/dist/zh-cn/office_strings.js +1 -0
  253. xlwings_server/static/vendor/@microsoft/office-js/dist/zh-hk/office_strings.js +8 -0
  254. xlwings_server/static/vendor/@microsoft/office-js/dist/zh-mo/office_strings.js +8 -0
  255. xlwings_server/static/vendor/@microsoft/office-js/dist/zh-sg/office_strings.js +8 -0
  256. xlwings_server/static/vendor/@microsoft/office-js/dist/zh-tw/office_strings.js +1 -0
  257. xlwings_server/static/vendor/axios/dist/axios.min.js +3 -0
  258. xlwings_server/static/vendor/axios/dist/axios.min.js.map +1 -0
  259. xlwings_server/static/vendor/bootstrap/LICENSE +21 -0
  260. xlwings_server/static/vendor/bootstrap/dist/js/bootstrap.bundle.min.js +7 -0
  261. xlwings_server/static/vendor/bootstrap/dist/js/bootstrap.bundle.min.js.map +1 -0
  262. xlwings_server/static/vendor/bootstrap-xlwings/dist/bootstrap-xlwings.min.css +12 -0
  263. xlwings_server/static/vendor/bootstrap-xlwings/dist/bootstrap-xlwings.min.css.map +1 -0
  264. xlwings_server/static/vendor/htmx-ext-head-support/head-support.js +144 -0
  265. xlwings_server/static/vendor/htmx-ext-loading-states/loading-states.js +184 -0
  266. xlwings_server/static/vendor/htmx.org/LICENSE +13 -0
  267. xlwings_server/static/vendor/htmx.org/dist/htmx.min.js +1 -0
  268. xlwings_server/static/vendor/socket.io/LICENSE +22 -0
  269. xlwings_server/static/vendor/socket.io/client-dist/socket.io.min.js +7 -0
  270. xlwings_server/static/vendor/socket.io/client-dist/socket.io.min.js.map +1 -0
  271. xlwings_server/templates/_book.html +8 -0
  272. xlwings_server/templates/alert_base.html +16 -0
  273. xlwings_server/templates/base.html +117 -0
  274. xlwings_server/templates/examples/alpine/README.md +26 -0
  275. xlwings_server/templates/examples/alpine/taskpane.html +47 -0
  276. xlwings_server/templates/examples/auth/README.md +38 -0
  277. xlwings_server/templates/examples/auth/protected.html +8 -0
  278. xlwings_server/templates/examples/auth/public.html +11 -0
  279. xlwings_server/templates/examples/excel_object_model/README.md +49 -0
  280. xlwings_server/templates/examples/excel_object_model/add_name_form.html +27 -0
  281. xlwings_server/templates/examples/hello_world/README.md +9 -0
  282. xlwings_server/templates/examples/hello_world/taskpane_hello.html +24 -0
  283. xlwings_server/templates/examples/htmx_form/README.md +44 -0
  284. xlwings_server/templates/examples/htmx_form/_greeting.html +6 -0
  285. xlwings_server/templates/examples/htmx_form/taskpane_htmx_form.html +21 -0
  286. xlwings_server/templates/examples/live_form_validation/README.md +60 -0
  287. xlwings_server/templates/examples/live_form_validation/add_name_form.html +33 -0
  288. xlwings_server/templates/examples/multi_app/README.md +34 -0
  289. xlwings_server/templates/examples/multi_app/taskpane1.html +7 -0
  290. xlwings_server/templates/examples/multi_app/taskpane2.html +7 -0
  291. xlwings_server/templates/examples/multi_app/taskpane_loader.html +5 -0
  292. xlwings_server/templates/examples/navigation/README.md +28 -0
  293. xlwings_server/templates/examples/navigation/_navigation.html +16 -0
  294. xlwings_server/templates/examples/navigation/taskpane_one.html +8 -0
  295. xlwings_server/templates/examples/navigation/taskpane_three.html +8 -0
  296. xlwings_server/templates/examples/navigation/taskpane_two.html +8 -0
  297. xlwings_server/templates/examples/pictures/README.md +42 -0
  298. xlwings_server/templates/examples/pictures/_picture.html +4 -0
  299. xlwings_server/templates/examples/pictures/taskpane_pictures.html +26 -0
  300. xlwings_server/templates/manifest.xml +155 -0
  301. xlwings_server/templates/taskpane.html +1 -0
  302. xlwings_server/templates/xlwings_alert.html +27 -0
  303. xlwings_server/templates.py +61 -0
  304. xlwings_server/utils.py +32 -0
  305. xlwings_server/wasm/__init__.py +0 -0
  306. xlwings_server/wasm/config.py +24 -0
  307. xlwings_server/wasm/main.py +236 -0
  308. xlwings_server/wasm/requirements.txt +5 -0
  309. xlwings_server-1.1.0.dist-info/METADATA +61 -0
  310. xlwings_server-1.1.0.dist-info/RECORD +313 -0
  311. xlwings_server-1.1.0.dist-info/WHEEL +4 -0
  312. xlwings_server-1.1.0.dist-info/entry_points.txt +2 -0
  313. 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,8 @@
1
+ {% extends "base.html" %}
2
+
3
+ {% block content %}
4
+ <div class="container-fluid pt-3 ps-3">
5
+ <h1>Protected Task Pane</h1>
6
+ <p>Your are logged in as {{ current_user.name }}.</p>
7
+ </div>
8
+ {% endblock content %}
@@ -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,6 @@
1
+ <h1>Result</h1>
2
+ {% if error %}
3
+ <div class="alert alert-danger" role="alert">{{ error }}</div>
4
+ {% else %}
5
+ <p>{{ greeting }}</p>
6
+ {% endif %}
@@ -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 "&nbsp;")
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">&nbsp;</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,7 @@
1
+ {% extends "base.html" %}
2
+
3
+ {% block content %}
4
+ <div class="container-fluid pt-3 ps-3">
5
+ <h1>App 1</h1>
6
+ </div>
7
+ {% endblock content %}
@@ -0,0 +1,7 @@
1
+ {% extends "base.html" %}
2
+
3
+ {% block content %}
4
+ <div class="container-fluid pt-3 ps-3">
5
+ <h1>App 2</h1>
6
+ </div>
7
+ {% endblock content %}
@@ -0,0 +1,5 @@
1
+ {% extends "base.html" %}
2
+
3
+ {% block content %}
4
+ <div x-data="appLoader" :hx-get="url" hx-target="body" hx-trigger="app:loadTaskpane"></div>
5
+ {% endblock content %}
@@ -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>
@@ -0,0 +1,8 @@
1
+ {% extends "base.html" %}
2
+
3
+ {% block content %}
4
+ <div class="container-fluid ps-3">
5
+ {% include "examples/navigation/_navigation.html" %}
6
+ <h1>This is Page 1</h1>
7
+ </div>
8
+ {% endblock content %}