rafa-engineering 0.0.1b1__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.
- rafa/__init__.py +463 -0
- rafa/actions/__init__.py +42 -0
- rafa/actions/decorators.py +204 -0
- rafa/actions/results.py +533 -0
- rafa/agent/__init__.py +40 -0
- rafa/agent/install.py +428 -0
- rafa/agent/scaffold.py +163 -0
- rafa/agent/skill/SKILL.md +156 -0
- rafa/agent/skill/references/access-and-permissions.md +126 -0
- rafa/agent/skill/references/actions.md +157 -0
- rafa/agent/skill/references/common-mistakes.md +274 -0
- rafa/agent/skill/references/entities-and-hierarchy.md +190 -0
- rafa/agent/skill/references/fields-and-layout.md +218 -0
- rafa/agent/skill/references/jobs-and-progress.md +105 -0
- rafa/agent/skill/references/maps-3d-documents-chats.md +175 -0
- rafa/agent/skill/references/testing-and-checking.md +187 -0
- rafa/agent/skill/references/validation-and-conditions.md +176 -0
- rafa/agent/skill/references/views-and-results.md +206 -0
- rafa/agent/templates/README.md.tmpl +34 -0
- rafa/agent/templates/gitignore.tmpl +5 -0
- rafa/agent/templates/package/__init__.py.tmpl +1 -0
- rafa/agent/templates/package/controller.py.tmpl +59 -0
- rafa/agent/templates/package/parametrization.py.tmpl +32 -0
- rafa/agent/templates/pyproject.toml.tmpl +20 -0
- rafa/agent/templates/tests/test_app.py.tmpl +44 -0
- rafa/auth.py +72 -0
- rafa/chat/__init__.py +26 -0
- rafa/chat/execution.py +221 -0
- rafa/chat/model.py +194 -0
- rafa/chat/service.py +353 -0
- rafa/chat/store.py +196 -0
- rafa/cli.py +541 -0
- rafa/cli_access.py +402 -0
- rafa/cli_agent.py +193 -0
- rafa/cli_dev.py +223 -0
- rafa/core/__init__.py +6 -0
- rafa/core/access.py +2915 -0
- rafa/core/app_roles.py +276 -0
- rafa/core/application.py +2717 -0
- rafa/core/calculations.py +253 -0
- rafa/core/controller.py +614 -0
- rafa/core/entity.py +419 -0
- rafa/core/field_permissions.py +146 -0
- rafa/core/jobs/__init__.py +0 -0
- rafa/core/jobs/execution.py +238 -0
- rafa/core/jobs/messages.py +218 -0
- rafa/core/jobs/model.py +242 -0
- rafa/core/jobs/progress.py +248 -0
- rafa/core/jobs/service.py +988 -0
- rafa/core/jobs/store.py +412 -0
- rafa/core/jobs/wire.py +73 -0
- rafa/core/parametrization.py +712 -0
- rafa/core/params.py +481 -0
- rafa/core/registry.py +215 -0
- rafa/core/services/__init__.py +42 -0
- rafa/core/services/_common.py +53 -0
- rafa/core/services/calculations.py +436 -0
- rafa/core/services/edit_locks.py +78 -0
- rafa/core/services/entities.py +754 -0
- rafa/core/services/revisions.py +200 -0
- rafa/core/services/summaries.py +113 -0
- rafa/core/steps.py +141 -0
- rafa/core/storage.py +370 -0
- rafa/core/summary.py +344 -0
- rafa/demo.py +88 -0
- rafa/documents/__init__.py +65 -0
- rafa/documents/_common.py +123 -0
- rafa/documents/_sandbox.py +607 -0
- rafa/documents/excel.py +264 -0
- rafa/documents/images.py +246 -0
- rafa/documents/pdf.py +83 -0
- rafa/documents/word.py +235 -0
- rafa/exceptions.py +257 -0
- rafa/fields/__init__.py +98 -0
- rafa/fields/autocomplete.py +128 -0
- rafa/fields/base.py +412 -0
- rafa/fields/buttons.py +181 -0
- rafa/fields/chat.py +160 -0
- rafa/fields/color.py +109 -0
- rafa/fields/containers.py +809 -0
- rafa/fields/date.py +249 -0
- rafa/fields/file.py +430 -0
- rafa/fields/geo.py +535 -0
- rafa/fields/geometry_select.py +275 -0
- rafa/fields/hidden.py +61 -0
- rafa/fields/layout.py +331 -0
- rafa/fields/multiselect.py +159 -0
- rafa/fields/numeric.py +524 -0
- rafa/fields/options.py +390 -0
- rafa/fields/output.py +149 -0
- rafa/fields/relationships.py +385 -0
- rafa/fields/text.py +221 -0
- rafa/geo.py +313 -0
- rafa/geometry/__init__.py +107 -0
- rafa/geometry/material.py +215 -0
- rafa/geometry/models.py +221 -0
- rafa/geometry/objects.py +1126 -0
- rafa/geometry/transform.py +177 -0
- rafa/geometry/vector.py +195 -0
- rafa/geometry/wire.py +278 -0
- rafa/layout/__init__.py +71 -0
- rafa/layout/base.py +46 -0
- rafa/layout/chat.py +43 -0
- rafa/layout/children.py +27 -0
- rafa/layout/containers.py +141 -0
- rafa/layout/elements.py +105 -0
- rafa/layout/geo.py +33 -0
- rafa/layout/inputs.py +173 -0
- rafa/map_tiles.py +268 -0
- rafa/messages.py +211 -0
- rafa/persistence/__init__.py +6 -0
- rafa/persistence/access_models.py +224 -0
- rafa/persistence/chat_models.py +93 -0
- rafa/persistence/deletion.py +198 -0
- rafa/persistence/dialects.py +96 -0
- rafa/persistence/edit_locks.py +322 -0
- rafa/persistence/files.py +486 -0
- rafa/persistence/job_models.py +207 -0
- rafa/persistence/models.py +361 -0
- rafa/persistence/params_json.py +154 -0
- rafa/persistence/repository.py +930 -0
- rafa/persistence/retention.py +507 -0
- rafa/persistence/session.py +302 -0
- rafa/persistence/storage_models.py +76 -0
- rafa/persistence/transfer.py +238 -0
- rafa/persistence/types.py +56 -0
- rafa/project.py +158 -0
- rafa/project_dependencies.py +233 -0
- rafa/server/__init__.py +0 -0
- rafa/server/api.py +45 -0
- rafa/server/auth.py +393 -0
- rafa/server/controllers.py +87 -0
- rafa/server/dependencies.py +112 -0
- rafa/server/dev.py +80 -0
- rafa/server/logs.py +80 -0
- rafa/server/main.py +511 -0
- rafa/server/middleware.py +229 -0
- rafa/server/oidc.py +525 -0
- rafa/server/params.py +101 -0
- rafa/server/purge.py +87 -0
- rafa/server/routes/__init__.py +1 -0
- rafa/server/routes/_common.py +80 -0
- rafa/server/routes/access.py +328 -0
- rafa/server/routes/admin.py +318 -0
- rafa/server/routes/calculations.py +268 -0
- rafa/server/routes/chats.py +188 -0
- rafa/server/routes/edit_locks.py +125 -0
- rafa/server/routes/entities.py +289 -0
- rafa/server/routes/jobs.py +389 -0
- rafa/server/routes/navigation.py +86 -0
- rafa/server/routes/revisions.py +86 -0
- rafa/server/routes/types.py +84 -0
- rafa/server/schemas.py +1151 -0
- rafa/server/security.py +454 -0
- rafa/server/themes.py +326 -0
- rafa/server/web/assets/ActionButton-Bf4Edlki.js +1 -0
- rafa/server/web/assets/ActionButton.vue_vue_type_script_setup_true_lang-D4XFensL.js +1 -0
- rafa/server/web/assets/ActionButtonInput-Fh_nzqPc.js +1 -0
- rafa/server/web/assets/ActionJobButton.vue_vue_type_script_setup_true_lang-DoDkgjyF.js +1 -0
- rafa/server/web/assets/AutocompleteInput-BZX1zQNq.js +1 -0
- rafa/server/web/assets/BooleanInput-Bwk7TmkZ.js +1 -0
- rafa/server/web/assets/BufferGeometryUtils-DCeCGp_k.js +1 -0
- rafa/server/web/assets/ChatPanel-CRGfj0rM.js +5 -0
- rafa/server/web/assets/ChatPanel-DV8X386K.css +1 -0
- rafa/server/web/assets/ChildrenView-BoHMn59N.js +1 -0
- rafa/server/web/assets/ColorInput-BPm4Z_Jb.js +1 -0
- rafa/server/web/assets/Column-BeMEmV70.js +1 -0
- rafa/server/web/assets/DateInput-BCCGUhNt.css +1 -0
- rafa/server/web/assets/DateInput-DoB9qbsx.js +1 -0
- rafa/server/web/assets/DynamicArrayInput-DMMS0Z-7.css +1 -0
- rafa/server/web/assets/DynamicArrayInput-_ZexTyhi.js +1 -0
- rafa/server/web/assets/EntityInput-DtkTtCvs.js +1 -0
- rafa/server/web/assets/FieldShell.vue_vue_type_script_setup_true_lang-D1Iio9Vx.js +1 -0
- rafa/server/web/assets/FileUpload-D0temXG6.js +1 -0
- rafa/server/web/assets/FlowList-BFQbYe4d.js +1 -0
- rafa/server/web/assets/FlowList-BJJKReYx.css +1 -0
- rafa/server/web/assets/GeoInput-B8mK3_to.js +1 -0
- rafa/server/web/assets/GeometrySelectInput-C-dllULO.js +1 -0
- rafa/server/web/assets/InlineMarkdown-273vK7EL.css +1 -0
- rafa/server/web/assets/InlineMarkdown-DZ6hRlXd.js +1 -0
- rafa/server/web/assets/ItemFields.vue_vue_type_script_setup_true_lang-oM-9Jbkr.js +1 -0
- rafa/server/web/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- rafa/server/web/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- rafa/server/web/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- rafa/server/web/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- rafa/server/web/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- rafa/server/web/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- rafa/server/web/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- rafa/server/web/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- rafa/server/web/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- rafa/server/web/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- rafa/server/web/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- rafa/server/web/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- rafa/server/web/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- rafa/server/web/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- rafa/server/web/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- rafa/server/web/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- rafa/server/web/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- rafa/server/web/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- rafa/server/web/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- rafa/server/web/assets/LineBreak-aRafznt0.js +1 -0
- rafa/server/web/assets/MapSelectInput-DSHaB30s.js +1 -0
- rafa/server/web/assets/MediaEmbed-BJ439byk.js +1 -0
- rafa/server/web/assets/Metric-CZNGA3xN.js +1 -0
- rafa/server/web/assets/MetricCard.vue_vue_type_script_setup_true_lang-C9JQb8Wv.js +1 -0
- rafa/server/web/assets/MultiFileInput-ZXboXAai.js +1 -0
- rafa/server/web/assets/NodeList.vue_vue_type_script_setup_true_lang-QazaRbQq.js +1 -0
- rafa/server/web/assets/NumberInput-C2W5shMF.js +1 -0
- rafa/server/web/assets/NumberInput-ClGTeHqr.css +1 -0
- rafa/server/web/assets/OutputText-BCN_LkxG.js +1 -0
- rafa/server/web/assets/Page-CaGMez-_.js +1 -0
- rafa/server/web/assets/Region.vue_vue_type_script_setup_true_lang-C5zmYcwf.js +1 -0
- rafa/server/web/assets/Row-Svp3fhrJ.js +1 -0
- rafa/server/web/assets/Section-Bxqg4axO.js +1 -0
- rafa/server/web/assets/SelectInput-3bMoZmLo.js +1 -0
- rafa/server/web/assets/Tab-DmT7FFbM.js +1 -0
- rafa/server/web/assets/TableInput-B6pu8pc-.css +1 -0
- rafa/server/web/assets/TableInput-DRy1zZlo.js +1 -0
- rafa/server/web/assets/Tabs-D_ly_8Cg.js +1 -0
- rafa/server/web/assets/TextBlock-DCx1b51J.js +1 -0
- rafa/server/web/assets/TextInput-ChR21tIl.js +1 -0
- rafa/server/web/assets/View-5zkwqki7.js +7 -0
- rafa/server/web/assets/View-B5J19S_i.css +1 -0
- rafa/server/web/assets/Workspace-BHmWCHUw.js +1 -0
- rafa/server/web/assets/Workspace-kQMd1Tiw.css +1 -0
- rafa/server/web/assets/_commonjsHelpers-CqkleIqs.js +1 -0
- rafa/server/web/assets/buildModel-FvbW_vi8.js +1 -0
- rafa/server/web/assets/fileRecords-J4dDztnY.js +1 -0
- rafa/server/web/assets/geometryPick-D2JWx8eh.js +1 -0
- rafa/server/web/assets/geometryScene-DBVxLCLP.js +4012 -0
- rafa/server/web/assets/index-BDd7wfsC.css +1 -0
- rafa/server/web/assets/index-BR16ovZa.js +81 -0
- rafa/server/web/assets/inter-cyrillic-400-normal-obahsSVq.woff2 +0 -0
- rafa/server/web/assets/inter-cyrillic-500-normal-BasfLYem.woff2 +0 -0
- rafa/server/web/assets/inter-cyrillic-600-normal-CWCymEST.woff2 +0 -0
- rafa/server/web/assets/inter-cyrillic-700-normal-CjBOestx.woff2 +0 -0
- rafa/server/web/assets/inter-cyrillic-ext-400-normal-BQZuk6qB.woff2 +0 -0
- rafa/server/web/assets/inter-cyrillic-ext-500-normal-B0yAr1jD.woff2 +0 -0
- rafa/server/web/assets/inter-cyrillic-ext-600-normal-Dfes3d0z.woff2 +0 -0
- rafa/server/web/assets/inter-cyrillic-ext-700-normal-BjwYoWNd.woff2 +0 -0
- rafa/server/web/assets/inter-greek-400-normal-B4URO6DV.woff2 +0 -0
- rafa/server/web/assets/inter-greek-500-normal-BIZE56-Y.woff2 +0 -0
- rafa/server/web/assets/inter-greek-600-normal-plRanbMR.woff2 +0 -0
- rafa/server/web/assets/inter-greek-700-normal-C3JjAnD8.woff2 +0 -0
- rafa/server/web/assets/inter-greek-ext-400-normal-DGGRlc-M.woff2 +0 -0
- rafa/server/web/assets/inter-greek-ext-500-normal-C4iEst2y.woff2 +0 -0
- rafa/server/web/assets/inter-greek-ext-600-normal-DRtmH8MT.woff2 +0 -0
- rafa/server/web/assets/inter-greek-ext-700-normal-qfdV9bQt.woff2 +0 -0
- rafa/server/web/assets/inter-latin-400-normal-C38fXH4l.woff2 +0 -0
- rafa/server/web/assets/inter-latin-500-normal-Cerq10X2.woff2 +0 -0
- rafa/server/web/assets/inter-latin-600-normal-LgqL8muc.woff2 +0 -0
- rafa/server/web/assets/inter-latin-700-normal-Yt3aPRUw.woff2 +0 -0
- rafa/server/web/assets/inter-latin-ext-400-normal-C1nco2VV.woff2 +0 -0
- rafa/server/web/assets/inter-latin-ext-500-normal-CV4jyFjo.woff2 +0 -0
- rafa/server/web/assets/inter-latin-ext-600-normal-D2bJ5OIk.woff2 +0 -0
- rafa/server/web/assets/inter-latin-ext-700-normal-Ca8adRJv.woff2 +0 -0
- rafa/server/web/assets/inter-vietnamese-400-normal-DMkecbls.woff2 +0 -0
- rafa/server/web/assets/inter-vietnamese-500-normal-DOriooB6.woff2 +0 -0
- rafa/server/web/assets/inter-vietnamese-600-normal-Cc8MFFhd.woff2 +0 -0
- rafa/server/web/assets/inter-vietnamese-700-normal-DlLaEgI2.woff2 +0 -0
- rafa/server/web/assets/jetbrains-mono-cyrillic-400-normal-BEIGL1Tu.woff2 +0 -0
- rafa/server/web/assets/jetbrains-mono-cyrillic-500-normal-DmUKJPL_.woff2 +0 -0
- rafa/server/web/assets/jetbrains-mono-greek-400-normal-C190GLew.woff2 +0 -0
- rafa/server/web/assets/jetbrains-mono-greek-500-normal-JpySY46c.woff2 +0 -0
- rafa/server/web/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
- rafa/server/web/assets/jetbrains-mono-latin-500-normal-BWZEU5yA.woff2 +0 -0
- rafa/server/web/assets/jetbrains-mono-latin-ext-400-normal-Bc8Ftmh3.woff2 +0 -0
- rafa/server/web/assets/jetbrains-mono-latin-ext-500-normal-Cut-4mMH.woff2 +0 -0
- rafa/server/web/assets/katex-BYjW4tYw.css +1 -0
- rafa/server/web/assets/katex-DhXJpUyf.js +261 -0
- rafa/server/web/assets/leafletChunk-wTN8pUxY.js +1 -0
- rafa/server/web/assets/leafletChunk-ySJ7tiBZ.css +1 -0
- rafa/server/web/assets/leafletMap-sOqlnmE2.js +2 -0
- rafa/server/web/assets/listbox-CB4ZAfo3.js +1 -0
- rafa/server/web/assets/loadGltf-3B6-WLUM.js +1 -0
- rafa/server/web/assets/loadIfc-XWq_7Qp9.js +6 -0
- rafa/server/web/assets/mapSelect-3T3UH25p.js +3 -0
- rafa/server/web/assets/material-symbols-outlined-latin-400-normal-C-3S2fI8.woff2 +0 -0
- rafa/server/web/assets/plotly.min-CSPuXaX0.js +3789 -0
- rafa/server/web/assets/web-ifc-BDaIXFUT.wasm +0 -0
- rafa/server/web/favicon.svg +1 -0
- rafa/server/web/index.html +20 -0
- rafa/server/web/theme-init.js +33 -0
- rafa/server/web/web-view-frame.html +154 -0
- rafa/server/worker_process.py +320 -0
- rafa/server/workers.py +473 -0
- rafa/settings.py +586 -0
- rafa/testing/__init__.py +397 -0
- rafa/testing/checks.py +803 -0
- rafa/testing/pytest_plugin.py +50 -0
- rafa/testing/screenshot.py +508 -0
- rafa/themes/__init__.py +11 -0
- rafa/themes/colors.py +181 -0
- rafa/themes/css.py +109 -0
- rafa/themes/files.py +143 -0
- rafa/themes/model.py +423 -0
- rafa/themes/tokens.py +124 -0
- rafa/ui/__init__.py +75 -0
- rafa/ui/adapters/__init__.py +31 -0
- rafa/ui/adapters/cli.py +652 -0
- rafa/ui/application.py +667 -0
- rafa/ui/context.py +153 -0
- rafa/ui/protocols.py +681 -0
- rafa/utils/__init__.py +29 -0
- rafa/utils/dicts.py +37 -0
- rafa/utils/memoization.py +312 -0
- rafa/utils/migrations.py +316 -0
- rafa/validation/__init__.py +22 -0
- rafa/validation/callbacks.py +187 -0
- rafa/validation/lookup.py +807 -0
- rafa/views/__init__.py +91 -0
- rafa/views/decorators.py +290 -0
- rafa/views/maps.py +990 -0
- rafa/views/results.py +1428 -0
- rafa/views/safe_html.py +100 -0
- rafa_engineering-0.0.1b1.dist-info/METADATA +175 -0
- rafa_engineering-0.0.1b1.dist-info/RECORD +320 -0
- rafa_engineering-0.0.1b1.dist-info/WHEEL +4 -0
- rafa_engineering-0.0.1b1.dist-info/entry_points.txt +5 -0
- rafa_engineering-0.0.1b1.dist-info/licenses/LICENSE +121 -0
rafa/__init__.py
ADDED
|
@@ -0,0 +1,463 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Rafa - an application framework for engineering web applications.
|
|
3
|
+
|
|
4
|
+
This module exports the public API for building applications. Names that were public
|
|
5
|
+
earlier but are not in ``__all__`` any more still import, with a ``DeprecationWarning`` that
|
|
6
|
+
names their new home (see ``_MOVED``).
|
|
7
|
+
|
|
8
|
+
Examples
|
|
9
|
+
--------
|
|
10
|
+
>>> from rafa import (
|
|
11
|
+
... Application,
|
|
12
|
+
... Controller,
|
|
13
|
+
... Parametrization,
|
|
14
|
+
... Tab,
|
|
15
|
+
... Section,
|
|
16
|
+
... NumberField,
|
|
17
|
+
... TextField,
|
|
18
|
+
... OptionField,
|
|
19
|
+
... DateField,
|
|
20
|
+
... Table,
|
|
21
|
+
... DynamicArray,
|
|
22
|
+
... Lookup,
|
|
23
|
+
... view,
|
|
24
|
+
... action,
|
|
25
|
+
... HTMLResult,
|
|
26
|
+
... SuccessResult,
|
|
27
|
+
... format_html,
|
|
28
|
+
... )
|
|
29
|
+
>>>
|
|
30
|
+
>>> class BeamParametrization(Parametrization):
|
|
31
|
+
... geometry = Tab("Geometry")
|
|
32
|
+
... geometry.width = NumberField(label="Width", default=0.3)
|
|
33
|
+
...
|
|
34
|
+
>>> class BeamController(Controller):
|
|
35
|
+
... label = "Beam"
|
|
36
|
+
... parametrization = BeamParametrization
|
|
37
|
+
...
|
|
38
|
+
... @view("Overview")
|
|
39
|
+
... def overview(self, params, entity, **kwargs):
|
|
40
|
+
... # format_html escapes the values: a name like "<B1>" shows as typed
|
|
41
|
+
... return HTMLResult(
|
|
42
|
+
... format_html("<h2>{}</h2><p>Width: {} m</p>", entity.name, params.geometry.width)
|
|
43
|
+
... )
|
|
44
|
+
...
|
|
45
|
+
... @action("Calculate")
|
|
46
|
+
... def calculate(self, params, entity, **kwargs):
|
|
47
|
+
... return SuccessResult(message="Done!")
|
|
48
|
+
>>>
|
|
49
|
+
>>> app = Application("sqlite:///app.db")
|
|
50
|
+
>>> app.register(BeamController)
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
import warnings as _warnings
|
|
54
|
+
from importlib import import_module as _import_module
|
|
55
|
+
from importlib.metadata import PackageNotFoundError
|
|
56
|
+
from importlib.metadata import version as _package_version
|
|
57
|
+
from typing import Any as _Any
|
|
58
|
+
|
|
59
|
+
# Actions
|
|
60
|
+
from rafa.actions.decorators import action
|
|
61
|
+
from rafa.actions.results import (
|
|
62
|
+
ActionResult,
|
|
63
|
+
ErrorResult,
|
|
64
|
+
FileResult,
|
|
65
|
+
OptimizationColumn,
|
|
66
|
+
OptimizationResult,
|
|
67
|
+
OptimizationResultElement,
|
|
68
|
+
SetParamsResult,
|
|
69
|
+
SuccessResult,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# Auth
|
|
73
|
+
from rafa.auth import LOCAL_USER, User
|
|
74
|
+
|
|
75
|
+
# Chats
|
|
76
|
+
from rafa.chat.model import ChatMessage, ChatReply, ChatSuggestion, ChatTurn, Conversation
|
|
77
|
+
|
|
78
|
+
# Core
|
|
79
|
+
from rafa.core.access import Role
|
|
80
|
+
from rafa.core.app_roles import AppRole, Permission
|
|
81
|
+
from rafa.core.application import Application
|
|
82
|
+
from rafa.core.calculations import CalculationLimitError
|
|
83
|
+
from rafa.core.controller import CalculationContext, Controller
|
|
84
|
+
from rafa.core.entity import Entity
|
|
85
|
+
from rafa.core.jobs.model import Job
|
|
86
|
+
from rafa.core.jobs.progress import CalculationStopped, Progress, ProgressUpdate
|
|
87
|
+
from rafa.core.parametrization import Parametrization
|
|
88
|
+
from rafa.core.params import MutableParams, Params
|
|
89
|
+
from rafa.core.services import DeletedEntity
|
|
90
|
+
from rafa.core.steps import StepCheck
|
|
91
|
+
from rafa.core.storage import Storage, StorageLimitError
|
|
92
|
+
from rafa.core.summary import SummaryItem, SummaryValue
|
|
93
|
+
|
|
94
|
+
# Exceptions
|
|
95
|
+
from rafa.exceptions import (
|
|
96
|
+
CircularRelationshipError,
|
|
97
|
+
ConflictError,
|
|
98
|
+
EditLockedError,
|
|
99
|
+
EntityNotFoundError,
|
|
100
|
+
InputsLockedError,
|
|
101
|
+
InputViolation,
|
|
102
|
+
InvalidParamsError,
|
|
103
|
+
JobNotFoundError,
|
|
104
|
+
MigrationError,
|
|
105
|
+
NotFoundError,
|
|
106
|
+
PermissionDeniedError,
|
|
107
|
+
RafaError,
|
|
108
|
+
StaleRevisionError,
|
|
109
|
+
UserError,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
# Fields
|
|
113
|
+
from rafa.fields.autocomplete import AutocompleteField
|
|
114
|
+
from rafa.fields.base import Field, FieldError
|
|
115
|
+
from rafa.fields.buttons import (
|
|
116
|
+
ActionButtonField,
|
|
117
|
+
DownloadButtonField,
|
|
118
|
+
OptimizationButtonField,
|
|
119
|
+
SetParamsButtonField,
|
|
120
|
+
)
|
|
121
|
+
from rafa.fields.chat import ChatField
|
|
122
|
+
from rafa.fields.color import ColorField
|
|
123
|
+
from rafa.fields.containers import DynamicArray, Table
|
|
124
|
+
from rafa.fields.date import DateField
|
|
125
|
+
from rafa.fields.file import FileField, FileValue, MultiFileField
|
|
126
|
+
from rafa.fields.geo import GeoPointField, GeoPolygonField, GeoPolylineField, MapSelectField
|
|
127
|
+
from rafa.fields.geometry_select import GeometryMultiSelectField, GeometrySelectField
|
|
128
|
+
from rafa.fields.hidden import HiddenField
|
|
129
|
+
from rafa.fields.layout import Image, LineBreak, Section, Step, Tab, Text
|
|
130
|
+
from rafa.fields.multiselect import MultiSelectField
|
|
131
|
+
from rafa.fields.numeric import IntegerField, NumberField
|
|
132
|
+
from rafa.fields.options import BooleanField, OptionField, OptionListElement
|
|
133
|
+
from rafa.fields.output import OutputField
|
|
134
|
+
from rafa.fields.relationships import (
|
|
135
|
+
ChildEntityMultiSelectField,
|
|
136
|
+
ChildEntityOptionField,
|
|
137
|
+
EntityField,
|
|
138
|
+
EntityMultiSelectField,
|
|
139
|
+
SiblingEntityMultiSelectField,
|
|
140
|
+
SiblingEntityOptionField,
|
|
141
|
+
)
|
|
142
|
+
from rafa.fields.text import TextAreaField, TextField
|
|
143
|
+
|
|
144
|
+
# Geo
|
|
145
|
+
from rafa.geo import GeoPath, GeoPoint, rd_to_wgs, wgs_to_rd
|
|
146
|
+
|
|
147
|
+
# Geometry (the objects are in rafa.geometry)
|
|
148
|
+
from rafa.geometry.models import IFCResult
|
|
149
|
+
from rafa.messages import Message, Messages, Status
|
|
150
|
+
|
|
151
|
+
# Persistence
|
|
152
|
+
from rafa.persistence.repository import CascadeMode
|
|
153
|
+
|
|
154
|
+
# Themes
|
|
155
|
+
from rafa.themes.model import Brand, FontFace, Fonts, Theme, ThemeError
|
|
156
|
+
|
|
157
|
+
# Utils
|
|
158
|
+
from rafa.utils.memoization import LRUCache, memoize
|
|
159
|
+
from rafa.utils.migrations import MigrationRegistry, ParamsMigrator
|
|
160
|
+
|
|
161
|
+
# Validation
|
|
162
|
+
from rafa.validation.lookup import (
|
|
163
|
+
And,
|
|
164
|
+
Condition,
|
|
165
|
+
IsEqual,
|
|
166
|
+
IsFalse,
|
|
167
|
+
IsNotEqual,
|
|
168
|
+
IsNotNone,
|
|
169
|
+
IsTrue,
|
|
170
|
+
Lookup,
|
|
171
|
+
LookupExpression,
|
|
172
|
+
Not,
|
|
173
|
+
Or,
|
|
174
|
+
RowLookup,
|
|
175
|
+
resolve_lookup,
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
# Views
|
|
179
|
+
from rafa.views.decorators import ViewLocation, ViewSpeed, metric, view
|
|
180
|
+
from rafa.views.maps import (
|
|
181
|
+
GeoJSONResult,
|
|
182
|
+
MapCircle,
|
|
183
|
+
MapFeature,
|
|
184
|
+
MapLabel,
|
|
185
|
+
MapLegend,
|
|
186
|
+
MapLine,
|
|
187
|
+
MapPoint,
|
|
188
|
+
MapPolygon,
|
|
189
|
+
MapPolyline,
|
|
190
|
+
MapResult,
|
|
191
|
+
map_features,
|
|
192
|
+
require_mapyta,
|
|
193
|
+
)
|
|
194
|
+
from rafa.views.results import (
|
|
195
|
+
ALL,
|
|
196
|
+
DataItem,
|
|
197
|
+
DataResult,
|
|
198
|
+
ErrorViewResult,
|
|
199
|
+
GeometryResult,
|
|
200
|
+
HTMLResult,
|
|
201
|
+
ImageResult,
|
|
202
|
+
MetricResult,
|
|
203
|
+
PDFResult,
|
|
204
|
+
PlotlyResult,
|
|
205
|
+
TableCell,
|
|
206
|
+
TableColumn,
|
|
207
|
+
TableResult,
|
|
208
|
+
ViewResult,
|
|
209
|
+
WebResult,
|
|
210
|
+
math_html,
|
|
211
|
+
)
|
|
212
|
+
from rafa.views.results import (
|
|
213
|
+
DataViewResult as DataViewResult, # older name of DataResult
|
|
214
|
+
)
|
|
215
|
+
from rafa.views.results import (
|
|
216
|
+
HTMLViewResult as HTMLViewResult, # older name of HTMLResult
|
|
217
|
+
)
|
|
218
|
+
from rafa.views.safe_html import SafeHTML, format_html, html_escape
|
|
219
|
+
|
|
220
|
+
try:
|
|
221
|
+
__version__ = _package_version("rafa-engineering")
|
|
222
|
+
except PackageNotFoundError: # pragma: no cover - only when running from an uninstalled tree
|
|
223
|
+
__version__ = "0.0.0+unknown"
|
|
224
|
+
|
|
225
|
+
__all__ = [
|
|
226
|
+
"__version__",
|
|
227
|
+
# Core
|
|
228
|
+
"Application",
|
|
229
|
+
"User",
|
|
230
|
+
"LOCAL_USER",
|
|
231
|
+
"Role",
|
|
232
|
+
"Permission",
|
|
233
|
+
"AppRole",
|
|
234
|
+
"Controller",
|
|
235
|
+
"CalculationContext",
|
|
236
|
+
"StepCheck",
|
|
237
|
+
"Progress",
|
|
238
|
+
"ProgressUpdate",
|
|
239
|
+
"CalculationStopped",
|
|
240
|
+
"Messages",
|
|
241
|
+
"Message",
|
|
242
|
+
"Status",
|
|
243
|
+
"Job",
|
|
244
|
+
"Entity",
|
|
245
|
+
"Parametrization",
|
|
246
|
+
"Params",
|
|
247
|
+
"MutableParams",
|
|
248
|
+
"SummaryItem",
|
|
249
|
+
"SummaryValue",
|
|
250
|
+
"Storage",
|
|
251
|
+
# Exceptions
|
|
252
|
+
"RafaError",
|
|
253
|
+
"NotFoundError",
|
|
254
|
+
"EntityNotFoundError",
|
|
255
|
+
"ConflictError",
|
|
256
|
+
"StaleRevisionError",
|
|
257
|
+
"InputsLockedError",
|
|
258
|
+
"EditLockedError",
|
|
259
|
+
"JobNotFoundError",
|
|
260
|
+
"InvalidParamsError",
|
|
261
|
+
"CalculationLimitError",
|
|
262
|
+
"CircularRelationshipError",
|
|
263
|
+
"MigrationError",
|
|
264
|
+
"InputViolation",
|
|
265
|
+
"UserError",
|
|
266
|
+
"PermissionDeniedError",
|
|
267
|
+
"StorageLimitError",
|
|
268
|
+
# Fields - Base
|
|
269
|
+
"Field",
|
|
270
|
+
"FieldError",
|
|
271
|
+
# Fields - Numeric
|
|
272
|
+
"NumberField",
|
|
273
|
+
"IntegerField",
|
|
274
|
+
# Fields - Text
|
|
275
|
+
"TextField",
|
|
276
|
+
"TextAreaField",
|
|
277
|
+
# Fields - Date
|
|
278
|
+
"DateField",
|
|
279
|
+
# Fields - Options
|
|
280
|
+
"BooleanField",
|
|
281
|
+
"OptionField",
|
|
282
|
+
"OptionListElement",
|
|
283
|
+
# Fields - Containers
|
|
284
|
+
"Table",
|
|
285
|
+
"DynamicArray",
|
|
286
|
+
# Fields - Output
|
|
287
|
+
"OutputField",
|
|
288
|
+
# Fields - Multi-select
|
|
289
|
+
"MultiSelectField",
|
|
290
|
+
# Fields - Hidden
|
|
291
|
+
"HiddenField",
|
|
292
|
+
# Fields - Autocomplete
|
|
293
|
+
"AutocompleteField",
|
|
294
|
+
# Fields - Color
|
|
295
|
+
"ColorField",
|
|
296
|
+
# Fields - File
|
|
297
|
+
"FileField",
|
|
298
|
+
"FileValue",
|
|
299
|
+
"MultiFileField",
|
|
300
|
+
# Fields - Geo
|
|
301
|
+
"GeoPointField",
|
|
302
|
+
"GeoPolylineField",
|
|
303
|
+
"GeoPolygonField",
|
|
304
|
+
"MapSelectField",
|
|
305
|
+
# Fields - Buttons
|
|
306
|
+
"ActionButtonField",
|
|
307
|
+
"DownloadButtonField",
|
|
308
|
+
"SetParamsButtonField",
|
|
309
|
+
"OptimizationButtonField",
|
|
310
|
+
# Fields - Chat
|
|
311
|
+
"ChatField",
|
|
312
|
+
# Fields - Relationships
|
|
313
|
+
"EntityField",
|
|
314
|
+
"EntityMultiSelectField",
|
|
315
|
+
"ChildEntityOptionField",
|
|
316
|
+
"ChildEntityMultiSelectField",
|
|
317
|
+
"SiblingEntityOptionField",
|
|
318
|
+
"SiblingEntityMultiSelectField",
|
|
319
|
+
# Fields - Selection in a geometry view
|
|
320
|
+
"GeometrySelectField",
|
|
321
|
+
"GeometryMultiSelectField",
|
|
322
|
+
# Fields - Layout
|
|
323
|
+
"Tab",
|
|
324
|
+
"Step",
|
|
325
|
+
"Section",
|
|
326
|
+
"Text",
|
|
327
|
+
"LineBreak",
|
|
328
|
+
"Image",
|
|
329
|
+
# Validation
|
|
330
|
+
"Lookup",
|
|
331
|
+
"LookupExpression",
|
|
332
|
+
"RowLookup",
|
|
333
|
+
"resolve_lookup",
|
|
334
|
+
# Visibility operators
|
|
335
|
+
"And",
|
|
336
|
+
"Or",
|
|
337
|
+
"Not",
|
|
338
|
+
"IsTrue",
|
|
339
|
+
"IsFalse",
|
|
340
|
+
"IsNotNone",
|
|
341
|
+
"IsEqual",
|
|
342
|
+
"IsNotEqual",
|
|
343
|
+
"Condition",
|
|
344
|
+
# Geo
|
|
345
|
+
"GeoPoint",
|
|
346
|
+
"GeoPath",
|
|
347
|
+
"rd_to_wgs",
|
|
348
|
+
"wgs_to_rd",
|
|
349
|
+
# Persistence
|
|
350
|
+
"CascadeMode",
|
|
351
|
+
"DeletedEntity",
|
|
352
|
+
# Themes
|
|
353
|
+
"Theme",
|
|
354
|
+
"Brand",
|
|
355
|
+
"Fonts",
|
|
356
|
+
"FontFace",
|
|
357
|
+
"ThemeError",
|
|
358
|
+
# Utils - Memoization
|
|
359
|
+
"LRUCache",
|
|
360
|
+
"memoize",
|
|
361
|
+
# Utils - Migrations
|
|
362
|
+
"MigrationRegistry",
|
|
363
|
+
"ParamsMigrator",
|
|
364
|
+
# Actions
|
|
365
|
+
"action",
|
|
366
|
+
"ActionResult",
|
|
367
|
+
"SuccessResult",
|
|
368
|
+
"ErrorResult",
|
|
369
|
+
"FileResult",
|
|
370
|
+
"SetParamsResult",
|
|
371
|
+
"OptimizationResult",
|
|
372
|
+
"OptimizationResultElement",
|
|
373
|
+
"OptimizationColumn",
|
|
374
|
+
# Chats
|
|
375
|
+
"ChatMessage",
|
|
376
|
+
"ChatReply",
|
|
377
|
+
"ChatSuggestion",
|
|
378
|
+
"ChatTurn",
|
|
379
|
+
"Conversation",
|
|
380
|
+
# Views
|
|
381
|
+
"view",
|
|
382
|
+
"metric",
|
|
383
|
+
"ViewLocation",
|
|
384
|
+
"ViewSpeed",
|
|
385
|
+
"ViewResult",
|
|
386
|
+
"HTMLResult",
|
|
387
|
+
"math_html",
|
|
388
|
+
"format_html",
|
|
389
|
+
"html_escape",
|
|
390
|
+
"SafeHTML",
|
|
391
|
+
"DataResult",
|
|
392
|
+
"DataItem",
|
|
393
|
+
"ErrorViewResult",
|
|
394
|
+
"MetricResult",
|
|
395
|
+
"PlotlyResult",
|
|
396
|
+
"GeometryResult",
|
|
397
|
+
"IFCResult",
|
|
398
|
+
"TableResult",
|
|
399
|
+
"TableCell",
|
|
400
|
+
"TableColumn",
|
|
401
|
+
"ImageResult",
|
|
402
|
+
"PDFResult",
|
|
403
|
+
"WebResult",
|
|
404
|
+
"ALL",
|
|
405
|
+
# Views - Maps
|
|
406
|
+
"MapResult",
|
|
407
|
+
"GeoJSONResult",
|
|
408
|
+
"MapFeature",
|
|
409
|
+
"MapPoint",
|
|
410
|
+
"MapLine",
|
|
411
|
+
"MapPolyline",
|
|
412
|
+
"MapPolygon",
|
|
413
|
+
"MapCircle",
|
|
414
|
+
"MapLabel",
|
|
415
|
+
"MapLegend",
|
|
416
|
+
"map_features",
|
|
417
|
+
"require_mapyta",
|
|
418
|
+
]
|
|
419
|
+
|
|
420
|
+
# Names that left the top-level API: still importable, with a DeprecationWarning.
|
|
421
|
+
# name -> (module, attribute)
|
|
422
|
+
_MOVED: dict[str, tuple[str, str]] = {
|
|
423
|
+
# The protocol layer for other front ends; the web app does not use it
|
|
424
|
+
**{
|
|
425
|
+
name: ("rafa.ui", name)
|
|
426
|
+
for name in (
|
|
427
|
+
"UIContext",
|
|
428
|
+
"FormRenderer",
|
|
429
|
+
"ViewRenderer",
|
|
430
|
+
"ActionHandler",
|
|
431
|
+
"EntityBrowser",
|
|
432
|
+
"NotificationHandler",
|
|
433
|
+
"UIApplication",
|
|
434
|
+
"DefaultUIContext",
|
|
435
|
+
)
|
|
436
|
+
},
|
|
437
|
+
# Internals of conditions, caching, validation and the decorators
|
|
438
|
+
"LookupContext": ("rafa.validation.lookup", "LookupContext"),
|
|
439
|
+
"resolve_visibility": ("rafa.validation.lookup", "resolve_visibility"),
|
|
440
|
+
"evaluate_condition": ("rafa.validation.lookup", "evaluate_condition"),
|
|
441
|
+
"get_view_cache": ("rafa.utils.memoization", "get_view_cache"),
|
|
442
|
+
"ActionDefinition": ("rafa.actions", "ActionDefinition"),
|
|
443
|
+
"ViewDefinition": ("rafa.views", "ViewDefinition"),
|
|
444
|
+
"ValidationResult": ("rafa.fields", "ValidationResult"),
|
|
445
|
+
# Renamed: pydantic has a ValidationError too
|
|
446
|
+
"ValidationError": ("rafa", "FieldError"),
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
def __getattr__(name: str) -> _Any:
|
|
451
|
+
"""Import a name that moved out of the top-level API, with a DeprecationWarning."""
|
|
452
|
+
if name not in _MOVED:
|
|
453
|
+
raise AttributeError(f"module 'rafa' has no attribute {name!r}")
|
|
454
|
+
module, attribute = _MOVED[name]
|
|
455
|
+
new = f"{module}.{attribute}" if module != "rafa" else f"rafa.{attribute}"
|
|
456
|
+
_warnings.warn(
|
|
457
|
+
f"rafa.{name} is deprecated; import {new} instead.",
|
|
458
|
+
DeprecationWarning,
|
|
459
|
+
stacklevel=2,
|
|
460
|
+
)
|
|
461
|
+
if module == "rafa":
|
|
462
|
+
return globals()[attribute]
|
|
463
|
+
return getattr(_import_module(module), attribute)
|
rafa/actions/__init__.py
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Action system for buttons and user interactions.
|
|
3
|
+
|
|
4
|
+
Actions are button-triggered operations defined on Controllers
|
|
5
|
+
that execute backend logic and return results to the UI.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from rafa.actions.decorators import (
|
|
9
|
+
ActionDefinition,
|
|
10
|
+
ActionLocation,
|
|
11
|
+
action,
|
|
12
|
+
get_action_definition,
|
|
13
|
+
is_action,
|
|
14
|
+
)
|
|
15
|
+
from rafa.actions.results import (
|
|
16
|
+
ActionResult,
|
|
17
|
+
ErrorResult,
|
|
18
|
+
FileResult,
|
|
19
|
+
OptimizationColumn,
|
|
20
|
+
OptimizationResult,
|
|
21
|
+
OptimizationResultElement,
|
|
22
|
+
SetParamsResult,
|
|
23
|
+
SuccessResult,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
__all__ = [
|
|
27
|
+
# Decorators
|
|
28
|
+
"action",
|
|
29
|
+
"ActionDefinition",
|
|
30
|
+
"ActionLocation",
|
|
31
|
+
"is_action",
|
|
32
|
+
"get_action_definition",
|
|
33
|
+
# Results
|
|
34
|
+
"ActionResult",
|
|
35
|
+
"SuccessResult",
|
|
36
|
+
"ErrorResult",
|
|
37
|
+
"FileResult",
|
|
38
|
+
"SetParamsResult",
|
|
39
|
+
"OptimizationResult",
|
|
40
|
+
"OptimizationResultElement",
|
|
41
|
+
"OptimizationColumn",
|
|
42
|
+
]
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Action decorators for defining button-triggered operations on Controllers.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from collections.abc import Callable
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from functools import wraps
|
|
8
|
+
from typing import Any, Literal, TypeVar, get_args
|
|
9
|
+
|
|
10
|
+
from rafa.actions.results import ActionResult
|
|
11
|
+
from rafa.core.calculations import check_timeout
|
|
12
|
+
|
|
13
|
+
ActionLocation = Literal["sidebar", "inspector"]
|
|
14
|
+
"""Where an action button is placed in the workspace."""
|
|
15
|
+
|
|
16
|
+
ACTION_LOCATIONS: tuple[str, ...] = get_args(ActionLocation)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class ActionDefinition:
|
|
21
|
+
"""
|
|
22
|
+
Metadata about an action method.
|
|
23
|
+
|
|
24
|
+
Stored on the method and used by the runtime to:
|
|
25
|
+
- Register actions for an entity type
|
|
26
|
+
- Display buttons in the UI
|
|
27
|
+
- Handle confirmation dialogs
|
|
28
|
+
|
|
29
|
+
Attributes
|
|
30
|
+
----------
|
|
31
|
+
label : str
|
|
32
|
+
Button label shown in UI.
|
|
33
|
+
method_name : str
|
|
34
|
+
Name of the decorated method.
|
|
35
|
+
description : str | None
|
|
36
|
+
Tooltip text.
|
|
37
|
+
confirmation_message : str | None
|
|
38
|
+
If set, shows confirmation dialog before executing.
|
|
39
|
+
dangerous : bool
|
|
40
|
+
If True, button gets warning styling (e.g., red color).
|
|
41
|
+
icon : str | None
|
|
42
|
+
Icon name (e.g., "play", "bolt").
|
|
43
|
+
location : ActionLocation
|
|
44
|
+
``"sidebar"`` (in the inputs panel, below the inputs) or ``"inspector"`` (in the
|
|
45
|
+
results panel, below the results).
|
|
46
|
+
validate_inputs : bool
|
|
47
|
+
Only run when every input is valid (default). ``False`` for actions that repair
|
|
48
|
+
the inputs, such as "reset to defaults".
|
|
49
|
+
timeout : float | None
|
|
50
|
+
Time limit in seconds; ``None`` uses the application's, ``0`` means none.
|
|
51
|
+
permission : str
|
|
52
|
+
What a user's role must allow to run it: ``"edit"`` (default, Editor), ``"read"``
|
|
53
|
+
(Viewer too, e.g. an export) or ``"manage"`` (Project admin). A ``SetParamsResult``
|
|
54
|
+
is saved only for an Editor.
|
|
55
|
+
locks_inputs : bool
|
|
56
|
+
Whether the entity's inputs are locked while the action is queued or running (D37):
|
|
57
|
+
saves, restores and other actions that save inputs are refused. Only for actions
|
|
58
|
+
whose ``permission`` is not ``"read"``. Default True.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
label: str
|
|
62
|
+
method_name: str
|
|
63
|
+
description: str | None
|
|
64
|
+
confirmation_message: str | None
|
|
65
|
+
dangerous: bool
|
|
66
|
+
icon: str | None = None
|
|
67
|
+
location: ActionLocation = "sidebar"
|
|
68
|
+
validate_inputs: bool = True
|
|
69
|
+
timeout: float | None = None
|
|
70
|
+
permission: str = "edit"
|
|
71
|
+
locks_inputs: bool = True
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def locks(self) -> bool:
|
|
75
|
+
"""Whether running it locks the inputs: ``locks_inputs`` and not a ``read`` action."""
|
|
76
|
+
return self.locks_inputs and self.permission != "read"
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
A = TypeVar("A", bound=Callable[..., ActionResult])
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def action(
|
|
83
|
+
label: str,
|
|
84
|
+
*,
|
|
85
|
+
description: str | None = None,
|
|
86
|
+
confirmation_message: str | None = None,
|
|
87
|
+
dangerous: bool = False,
|
|
88
|
+
icon: str | None = None,
|
|
89
|
+
location: ActionLocation = "sidebar",
|
|
90
|
+
validate_inputs: bool = True,
|
|
91
|
+
timeout: float | None = None,
|
|
92
|
+
permission: str = "edit",
|
|
93
|
+
locks_inputs: bool = True,
|
|
94
|
+
) -> Callable[[A], A]:
|
|
95
|
+
"""
|
|
96
|
+
Decorator to mark a method as an action.
|
|
97
|
+
|
|
98
|
+
Actions are button-triggered operations that execute backend logic
|
|
99
|
+
and return a result to the UI.
|
|
100
|
+
|
|
101
|
+
Parameters
|
|
102
|
+
----------
|
|
103
|
+
label : str
|
|
104
|
+
Button label shown in UI.
|
|
105
|
+
description : str | None, optional
|
|
106
|
+
Tooltip/help text.
|
|
107
|
+
confirmation_message : str | None, optional
|
|
108
|
+
If set, shows "Are you sure?" dialog with this message.
|
|
109
|
+
dangerous : bool, optional
|
|
110
|
+
If True, button gets warning styling. Default False.
|
|
111
|
+
icon : str | None, optional
|
|
112
|
+
Icon name (Material Symbols, e.g. ``"bolt"``).
|
|
113
|
+
location : {"sidebar", "inspector"}, optional
|
|
114
|
+
``"sidebar"`` puts the button in the inputs panel, below the inputs;
|
|
115
|
+
``"inspector"`` in the results panel, below the results. Default ``"sidebar"``.
|
|
116
|
+
validate_inputs : bool, optional
|
|
117
|
+
Only run when every input is valid; otherwise the action returns an
|
|
118
|
+
``ErrorResult`` that lists the invalid fields. Default True. Set it to False for
|
|
119
|
+
actions that repair the inputs, such as "reset to defaults".
|
|
120
|
+
timeout : float | None, optional
|
|
121
|
+
Seconds the action may calculate. On the server it is then stopped (D37) and
|
|
122
|
+
returns an ``ErrorResult`` "No result within … s."; its ``SetParamsResult`` is never
|
|
123
|
+
saved. ``None`` (default) uses the application's limit
|
|
124
|
+
(``RAFA_CALCULATION_TIMEOUT`` on the server), ``0`` means no limit.
|
|
125
|
+
permission : str, optional
|
|
126
|
+
What a user's role must allow to run the action (access control, D36):
|
|
127
|
+
``"edit"`` (default: Editors and Project admins), ``"read"`` (Viewers too; for
|
|
128
|
+
actions that change nothing, such as an export) or ``"manage"`` (Project admins).
|
|
129
|
+
Whatever it allows, a ``SetParamsResult`` is saved only for an Editor. The
|
|
130
|
+
controller's ``check_definition()`` refuses other names.
|
|
131
|
+
locks_inputs : bool, optional
|
|
132
|
+
Lock the entity's inputs while the action is queued or running (default True): on
|
|
133
|
+
the server, saves, restores and other actions that save inputs are refused (409)
|
|
134
|
+
until it ends, so it never saves over a change made meanwhile, nor another over
|
|
135
|
+
its own. ``False`` for an action that never saves inputs (no ``SetParamsResult``,
|
|
136
|
+
no save through ``kwargs["app"]``). Actions with ``permission="read"`` never lock.
|
|
137
|
+
|
|
138
|
+
Returns
|
|
139
|
+
-------
|
|
140
|
+
Callable
|
|
141
|
+
Decorator function.
|
|
142
|
+
|
|
143
|
+
Raises
|
|
144
|
+
------
|
|
145
|
+
ValueError
|
|
146
|
+
If ``location`` is not one of the supported locations, ``timeout`` is
|
|
147
|
+
negative, or ``locks_inputs`` is not a bool.
|
|
148
|
+
"""
|
|
149
|
+
check_timeout(timeout, f"@action({label!r})")
|
|
150
|
+
if not isinstance(locks_inputs, bool):
|
|
151
|
+
raise ValueError(
|
|
152
|
+
f"@action({label!r}): locks_inputs must be True or False, got {locks_inputs!r}"
|
|
153
|
+
)
|
|
154
|
+
if location not in ACTION_LOCATIONS:
|
|
155
|
+
raise ValueError(
|
|
156
|
+
f"@action({label!r}): unknown location {location!r}. "
|
|
157
|
+
f"Use one of: {', '.join(ACTION_LOCATIONS)}"
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
def decorator(func: A) -> A:
|
|
161
|
+
# Create action definition
|
|
162
|
+
action_def = ActionDefinition(
|
|
163
|
+
label=label,
|
|
164
|
+
method_name=func.__name__,
|
|
165
|
+
description=description,
|
|
166
|
+
confirmation_message=confirmation_message,
|
|
167
|
+
dangerous=dangerous,
|
|
168
|
+
icon=icon,
|
|
169
|
+
location=location,
|
|
170
|
+
validate_inputs=validate_inputs,
|
|
171
|
+
timeout=timeout,
|
|
172
|
+
permission=permission,
|
|
173
|
+
locks_inputs=locks_inputs,
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
# Attach metadata to function
|
|
177
|
+
func._action_definition = action_def
|
|
178
|
+
|
|
179
|
+
@wraps(func)
|
|
180
|
+
def wrapper(*args: Any, **kwargs: Any) -> ActionResult:
|
|
181
|
+
result = func(*args, **kwargs)
|
|
182
|
+
if not isinstance(result, ActionResult):
|
|
183
|
+
raise TypeError(
|
|
184
|
+
f"Action '{func.__name__}' must return an ActionResult, "
|
|
185
|
+
f"got {type(result).__name__}"
|
|
186
|
+
)
|
|
187
|
+
return result
|
|
188
|
+
|
|
189
|
+
# Preserve metadata on wrapper
|
|
190
|
+
wrapper._action_definition = action_def # type: ignore[attr-defined]
|
|
191
|
+
|
|
192
|
+
return wrapper # type: ignore[return-value]
|
|
193
|
+
|
|
194
|
+
return decorator
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def is_action(obj: Any) -> bool:
|
|
198
|
+
"""Check if an object is an action method."""
|
|
199
|
+
return callable(obj) and hasattr(obj, "_action_definition")
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def get_action_definition(method: Callable[..., Any]) -> ActionDefinition | None:
|
|
203
|
+
"""Get the ActionDefinition for an action method."""
|
|
204
|
+
return getattr(method, "_action_definition", None)
|