Skip to content

Commit 5354584

Browse files
authored
Declarative Settings UI API (Nextcloud 29) (#222)
Signed-off-by: Alexander Piskun <bigcat88@icloud.com>
1 parent c6e4aa9 commit 5354584

File tree

10 files changed

+412
-3
lines changed

10 files changed

+412
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file.
77
### Added
88

99
- set_handlers: `models_to_fetch` can now accept direct links to a files to download. #217
10+
- DeclarativeSettings API for Nextcloud 29. #222
1011

1112
### Changed
1213

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ Python library that provides a robust and well-documented API that allows develo
3535
| User & Weather status |||||
3636
| Other APIs*** |||||
3737
| Talk Bot API* | N/A ||||
38+
| Settings UI API* | N/A | N/A | N/A ||
3839
| AI Providers API** | N/A | N/A | N/A ||
3940

4041
&ast;_available only for **NextcloudApp**_<br>

docs/NextcloudUiApp.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,20 @@ Here we will simply describe in detail what happens in the example.
1919
)
2020
nc.ui.resources.set_script("top_menu", "first_menu", "js/ui_example-main")
2121
nc.ui.top_menu.register("first_menu", "UI example", "img/icon.svg")
22+
if nc.srv_version["major"] >= 29:
23+
nc.ui.settings.register_form(SETTINGS_EXAMPLE)
2224
2325
**set_initial_state** is analogue of PHP ``OCP\AppFramework\Services\IInitialState::provideInitialState``
2426

2527
**set_script** is analogue of PHP ``Util::addScript``
2628

2729
There is also **set_style** (``Util::addStyle``) that can be used for CSS files and works the same way as **set_script**.
2830

31+
Starting with Nextcloud **29** AppAPI supports declaring Settings UI, with very simple and robust API.
32+
33+
Settings values you declare will be saved to ``preferences_ex`` or ``appconfig_ex`` tables and can be retrieved using
34+
:py:class:`nc_py_api._preferences_ex.PreferencesExAPI` or :py:class:`nc_py_api._preferences_ex.AppConfigExAPI` APIs.
35+
2936
Backend
3037
-------
3138

docs/reference/ExApp.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,18 @@ UI methods should be accessed with the help of :class:`~nc_py_api.nextcloud.Next
5757
.. autoclass:: nc_py_api.ex_app.ui.resources.UiStyle
5858
:members:
5959

60+
.. autoclass:: nc_py_api.ex_app.ui.settings.SettingsField
61+
:members:
62+
63+
.. autoclass:: nc_py_api.ex_app.ui.settings.SettingsForm
64+
:members:
65+
66+
.. autoclass:: nc_py_api.ex_app.ui.settings.SettingsFieldType
67+
:members:
68+
69+
.. autoclass:: nc_py_api.ex_app.ui.settings._DeclarativeSettingsAPI
70+
:members:
71+
6072
.. autoclass:: nc_py_api.ex_app.providers.providers.ProvidersApi
6173
:members:
6274

examples/as_app/ui_example/lib/main.py

Lines changed: 134 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,14 @@
88
from pydantic import BaseModel
99

1010
from nc_py_api import NextcloudApp
11-
from nc_py_api.ex_app import nc_app, run_app, set_handlers
11+
from nc_py_api.ex_app import (
12+
SettingsField,
13+
SettingsFieldType,
14+
SettingsForm,
15+
nc_app,
16+
run_app,
17+
set_handlers,
18+
)
1219

1320

1421
@asynccontextmanager
@@ -19,6 +26,130 @@ async def lifespan(_app: FastAPI):
1926

2027
APP = FastAPI(lifespan=lifespan)
2128

29+
SETTINGS_EXAMPLE = SettingsForm(
30+
id="settings_example",
31+
section_type="admin",
32+
section_id="ai_integration_team",
33+
title="Example of declarative settings",
34+
description="These fields are rendered dynamically from declarative schema",
35+
fields=[
36+
SettingsField(
37+
id="field1",
38+
title="Multi-selection",
39+
description="Select some option setting",
40+
type=SettingsFieldType.MULTI_SELECT,
41+
default=["foo", "bar"],
42+
placeholder="Select some multiple options",
43+
options=["foo", "bar", "baz"],
44+
),
45+
SettingsField(
46+
id="some_real_setting",
47+
title="Choose init status check background job interval",
48+
description="How often ExApp should check for initialization status",
49+
type=SettingsFieldType.RADIO,
50+
default="40m",
51+
placeholder="Choose init status check background job interval",
52+
options={
53+
"Each 40 minutes": "40m",
54+
"Each 60 minutes": "60m",
55+
"Each 120 minutes": "120m",
56+
"Each day": f"{60 * 24}m",
57+
},
58+
),
59+
SettingsField(
60+
id="test_ex_app_field_1",
61+
title="Default text field",
62+
description="Set some simple text setting",
63+
type=SettingsFieldType.TEXT,
64+
default="foo",
65+
placeholder="Enter text setting",
66+
),
67+
SettingsField(
68+
id="test_ex_app_field_1_1",
69+
title="Email field",
70+
description="Set email config",
71+
type=SettingsFieldType.EMAIL,
72+
default="",
73+
placeholder="Enter email",
74+
),
75+
SettingsField(
76+
id="test_ex_app_field_1_2",
77+
title="Tel field",
78+
description="Set tel config",
79+
type=SettingsFieldType.TEL,
80+
default="",
81+
placeholder="Enter your tel",
82+
),
83+
SettingsField(
84+
id="test_ex_app_field_1_3",
85+
title="Url (website) field",
86+
description="Set url config",
87+
type=SettingsFieldType.URL,
88+
default="",
89+
placeholder="Enter url",
90+
),
91+
SettingsField(
92+
id="test_ex_app_field_1_4",
93+
title="Number field",
94+
description="Set number config",
95+
type=SettingsFieldType.NUMBER,
96+
default=0,
97+
placeholder="Enter number value",
98+
),
99+
SettingsField(
100+
id="test_ex_app_field_2",
101+
title="Password",
102+
description="Set some secure value setting",
103+
type=SettingsFieldType.PASSWORD,
104+
default="",
105+
placeholder="Set secure value",
106+
),
107+
SettingsField(
108+
id="test_ex_app_field_3",
109+
title="Selection",
110+
description="Select some option setting",
111+
type=SettingsFieldType.SELECT,
112+
default="foo",
113+
placeholder="Select some option setting",
114+
options=["foo", "bar", "baz"],
115+
),
116+
SettingsField(
117+
id="test_ex_app_field_3",
118+
title="Selection",
119+
description="Select some option setting",
120+
type=SettingsFieldType.SELECT,
121+
default="foo",
122+
placeholder="Select some option setting",
123+
options=["foo", "bar", "baz"],
124+
),
125+
SettingsField(
126+
id="test_ex_app_field_4",
127+
title="Toggle something",
128+
description="Select checkbox option setting",
129+
type=SettingsFieldType.CHECKBOX,
130+
default=False,
131+
label="Verify something if enabled",
132+
),
133+
SettingsField(
134+
id="test_ex_app_field_5",
135+
title="Multiple checkbox toggles, describing one setting",
136+
description="Select checkbox option setting",
137+
type=SettingsFieldType.MULTI_CHECKBOX,
138+
default={"foo": True, "bar": True},
139+
options={"Foo": "foo", "Bar": "bar", "Baz": "baz", "Qux": "qux"},
140+
),
141+
SettingsField(
142+
id="test_ex_app_field_6",
143+
title="Radio toggles, describing one setting like single select",
144+
description="Select radio option setting",
145+
type=SettingsFieldType.RADIO,
146+
label="Select single toggle",
147+
default="foo",
148+
options={"First radio": "foo", "Second radio": "bar", "Third radie": "baz"},
149+
),
150+
],
151+
)
152+
22153

23154
def enabled_handler(enabled: bool, nc: NextcloudApp) -> str:
24155
print(f"enabled={enabled}")
@@ -28,6 +159,8 @@ def enabled_handler(enabled: bool, nc: NextcloudApp) -> str:
28159
)
29160
nc.ui.resources.set_script("top_menu", "first_menu", "js/ui_example-main")
30161
nc.ui.top_menu.register("first_menu", "UI example", "img/icon.svg")
162+
if nc.srv_version["major"] >= 29:
163+
nc.ui.settings.register_form(SETTINGS_EXAMPLE)
31164
return ""
32165

33166

nc_py_api/_preferences_ex.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ async def delete(self, keys: str | list[str], not_fail=True) -> None:
106106

107107

108108
class PreferencesExAPI(_BasicAppCfgPref):
109-
"""User specific preferences API."""
109+
"""User specific preferences API, avalaible as **nc.preferences_ex**."""
110110

111111
_url_suffix = "ex-app/preference"
112112

@@ -134,7 +134,7 @@ async def set_value(self, key: str, value: str) -> None:
134134

135135

136136
class AppConfigExAPI(_BasicAppCfgPref):
137-
"""Non-user(App) specific preferences API."""
137+
"""Non-user(App) specific preferences API, avalaible as **nc.appconfig_ex**."""
138138

139139
_url_suffix = "ex-app/config"
140140

nc_py_api/ex_app/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@
1111
)
1212
from .misc import get_model_path, persistent_storage, verify_version
1313
from .ui.files_actions import UiActionFileInfo
14+
from .ui.settings import SettingsField, SettingsFieldType, SettingsForm
1415
from .uvicorn_fastapi import run_app

0 commit comments

Comments
 (0)