flowbase-cli 0.1.15__tar.gz → 0.1.16__tar.gz
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.
- {flowbase_cli-0.1.15 → flowbase_cli-0.1.16}/PKG-INFO +74 -1
- {flowbase_cli-0.1.15 → flowbase_cli-0.1.16}/README.md +73 -0
- {flowbase_cli-0.1.15 → flowbase_cli-0.1.16}/pyproject.toml +1 -1
- {flowbase_cli-0.1.15 → flowbase_cli-0.1.16}/src/flowbase_cli/__init__.py +1 -1
- {flowbase_cli-0.1.15 → flowbase_cli-0.1.16}/src/flowbase_cli/endpoints.py +64 -5
- {flowbase_cli-0.1.15 → flowbase_cli-0.1.16}/src/flowbase_cli/main.py +68 -0
- {flowbase_cli-0.1.15 → flowbase_cli-0.1.16}/src/flowbase_cli.egg-info/PKG-INFO +74 -1
- {flowbase_cli-0.1.15 → flowbase_cli-0.1.16}/src/flowbase_cli.egg-info/SOURCES.txt +1 -0
- {flowbase_cli-0.1.15 → flowbase_cli-0.1.16}/tests/test_cli.py +1 -1
- flowbase_cli-0.1.16/tests/test_iframes.py +30 -0
- {flowbase_cli-0.1.15 → flowbase_cli-0.1.16}/setup.cfg +0 -0
- {flowbase_cli-0.1.15 → flowbase_cli-0.1.16}/src/flowbase_cli/guide.py +0 -0
- {flowbase_cli-0.1.15 → flowbase_cli-0.1.16}/src/flowbase_cli.egg-info/dependency_links.txt +0 -0
- {flowbase_cli-0.1.15 → flowbase_cli-0.1.16}/src/flowbase_cli.egg-info/entry_points.txt +0 -0
- {flowbase_cli-0.1.15 → flowbase_cli-0.1.16}/src/flowbase_cli.egg-info/top_level.txt +0 -0
- {flowbase_cli-0.1.15 → flowbase_cli-0.1.16}/tests/test_autonomy.py +0 -0
- {flowbase_cli-0.1.15 → flowbase_cli-0.1.16}/tests/test_recent_commands.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flowbase-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.16
|
|
4
4
|
Summary: Command line client for the FlowBase OpenAPI
|
|
5
5
|
Author: DeepFlowAI
|
|
6
6
|
License: Apache-2.0
|
|
@@ -160,6 +160,14 @@ flowbase objects cli-edit-policy update obj_xxx --json '{"baseRevision":4,"polic
|
|
|
160
160
|
|
|
161
161
|
`records create` returns `{recordId}`; use it with `records get`.
|
|
162
162
|
|
|
163
|
+
To add existing objects to an application, pass their IDs with `--object-ids`:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
flowbase apps add-objects app_xxx --object-ids obj_a,obj_b
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Use a comma-separated list for multiple objects. Object IDs are not positional arguments. Run `flowbase docs show apps.objects.add` for the endpoint details.
|
|
170
|
+
|
|
163
171
|
Record `values` keys are **field keys** (`name`), not internal IDs (`fld_...`). IDs are `obj_`/`fld_`/`dsh_`/`wfl_`/`pag_`/`reg_`/`cmp_`-prefixed; see `docs catalogs id-prefixes`.
|
|
164
172
|
|
|
165
173
|
### 6.2 Edit and publish configuration on a test environment
|
|
@@ -289,3 +297,68 @@ Transport requests time out after 60 seconds. A lost write response has an unkno
|
|
|
289
297
|
- `flowbase docs catalogs workflow-python`: record creation examples and failed-task retry. `workflows python-runtime OBJECT new` discovers current object bindings; `workflows executions` includes Python attempts, logs and `canRetry`.
|
|
290
298
|
|
|
291
299
|
Use `records list OBJECT --view-id VIEW --view-layout` for tree/Gantt projections; the default remains a flat list. `records update` accepts `updatedAt` and `planViewId` in its JSON body for version-checked plan edits. Formula validation/trials require both metadata read and record read; workflow retry requires both metadata write and record write and explicit CLI confirmation (`--yes` in automation).
|
|
300
|
+
|
|
301
|
+
### Reusable iframe configuration (4.11)
|
|
302
|
+
|
|
303
|
+
`flowbase iframes list|get|create|update|delete` manages environment-specific iframe drafts. Create/update use `--json-file`; fields are `label`, `icon` (default `IconWorld`), `color` (default `#2563EB`), and a complete HTTPS `url` without credentials. Update and delete require `baseRevision` from `iframes get`; deletion also requires confirmation (`--yes` for noninteractive use).
|
|
304
|
+
|
|
305
|
+
```bash
|
|
306
|
+
flowbase iframes create --json-file iframe.json
|
|
307
|
+
flowbase iframes get ifr_example
|
|
308
|
+
flowbase iframes update ifr_example --json-file iframe-update.json
|
|
309
|
+
flowbase apps add-iframes app_example ifr_example
|
|
310
|
+
flowbase apps set-iframe-group app_example ifr_example --group-id grp_example
|
|
311
|
+
flowbase apps set-iframe-group app_example ifr_example --ungrouped
|
|
312
|
+
flowbase apps reorder-members app_example --json '{"items":[{"type":"iframe","id":"ifr_example"}]}'
|
|
313
|
+
flowbase apps remove-iframe app_example ifr_example --yes
|
|
314
|
+
flowbase iframes delete ifr_example --json '{"baseRevision":12}' --yes
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
Removal only unlinks one app. Deletion unlinks all apps atomically. Changes follow the existing commit/release/rollback workflow; they do not fetch, proxy or modify the external website. API keys use `metadata:read`/`metadata:write`; browser roles use `iframe.manage` for shared resources and `app.manage` for app associations.
|
|
318
|
+
|
|
319
|
+
### Custom object views (4.12)
|
|
320
|
+
|
|
321
|
+
Read `flowbase docs catalogs custom-views` and `flowbase views list OBJECT` first. Save the following as `view.json`, replacing `baseRevision` with the current `draftRevision`:
|
|
322
|
+
|
|
323
|
+
```json
|
|
324
|
+
{
|
|
325
|
+
"baseRevision": 4,
|
|
326
|
+
"name": "Custom overview",
|
|
327
|
+
"enabled": false,
|
|
328
|
+
"defaultFieldIds": [],
|
|
329
|
+
"displayMode": "custom",
|
|
330
|
+
"custom": {
|
|
331
|
+
"runtimeVersion": "cv1",
|
|
332
|
+
"source": "import React from 'react'; export default function View(){return <div>Hello</div>}"
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
```bash
|
|
338
|
+
flowbase views create obj_example --json-file view.json
|
|
339
|
+
flowbase views list obj_example
|
|
340
|
+
flowbase views update obj_example viw_example --json-file view.json
|
|
341
|
+
flowbase views set-enabled obj_example viw_example --base-revision 6 --enabled --yes
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Use the revision returned by the preceding write, rather than the example numbers. Custom views start disabled; preview in the browser and enable when ready. Updates replace the writable snapshot: preserve `custom.source`, `custom.runtimeVersion`, `displayMode`, filters and other configuration from `views list`, excluding the response-only `id` and `status`. Built-in/custom view types cannot be converted. JSX source is limited to 512 KiB UTF-8; the runtime supports `react`, `three` and `flowbase`. CLI configuration does not execute browser previews.
|
|
345
|
+
|
|
346
|
+
### Record detail embedded pages (4.13)
|
|
347
|
+
|
|
348
|
+
`flowbase docs catalogs page-components` documents `recordEmbed`, supported at the top level or inside tabs of a detail Page. Add this component to an existing region column (or a tab's `components`):
|
|
349
|
+
|
|
350
|
+
```json
|
|
351
|
+
{
|
|
352
|
+
"kind": "recordEmbed",
|
|
353
|
+
"label": "External panel",
|
|
354
|
+
"showTitle": true,
|
|
355
|
+
"url": "https://example.com/panel",
|
|
356
|
+
"height": 480,
|
|
357
|
+
"allowRead": false,
|
|
358
|
+
"allowedFieldIds": []
|
|
359
|
+
}
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
Read `flowbase pages get PAGE`, preserve the existing components and IDs, and remove the read-only Page keys listed in `docs catalogs page-components`. Wrap the editable snapshot as `{"baseRevision":4,"page":{...}}`, then use `flowbase pages update PAGE --json-file page.json` (or `pages create --json-file page.json` for a new detail Page). For creation, omit the Page ID and IDs of new regions/components so the server allocates them.
|
|
363
|
+
|
|
364
|
+
Height must be an integer from 240 to 1600. URLs must use external HTTPS and exclude credentials, identity/context parameters and templates. To permit SDK reads, set `allowRead: true` and select at least one unique active field ID in `allowedFieldIds`; current record/field permissions still apply. The browser SDK is `/sdk/record-embed.v1.js`. The CLI configures the component; rendering and SDK calls run in the browser. `flowbase-user` has no metadata management commands.
|
|
@@ -151,6 +151,14 @@ flowbase objects cli-edit-policy update obj_xxx --json '{"baseRevision":4,"polic
|
|
|
151
151
|
|
|
152
152
|
`records create` returns `{recordId}`; use it with `records get`.
|
|
153
153
|
|
|
154
|
+
To add existing objects to an application, pass their IDs with `--object-ids`:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
flowbase apps add-objects app_xxx --object-ids obj_a,obj_b
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Use a comma-separated list for multiple objects. Object IDs are not positional arguments. Run `flowbase docs show apps.objects.add` for the endpoint details.
|
|
161
|
+
|
|
154
162
|
Record `values` keys are **field keys** (`name`), not internal IDs (`fld_...`). IDs are `obj_`/`fld_`/`dsh_`/`wfl_`/`pag_`/`reg_`/`cmp_`-prefixed; see `docs catalogs id-prefixes`.
|
|
155
163
|
|
|
156
164
|
### 6.2 Edit and publish configuration on a test environment
|
|
@@ -280,3 +288,68 @@ Transport requests time out after 60 seconds. A lost write response has an unkno
|
|
|
280
288
|
- `flowbase docs catalogs workflow-python`: record creation examples and failed-task retry. `workflows python-runtime OBJECT new` discovers current object bindings; `workflows executions` includes Python attempts, logs and `canRetry`.
|
|
281
289
|
|
|
282
290
|
Use `records list OBJECT --view-id VIEW --view-layout` for tree/Gantt projections; the default remains a flat list. `records update` accepts `updatedAt` and `planViewId` in its JSON body for version-checked plan edits. Formula validation/trials require both metadata read and record read; workflow retry requires both metadata write and record write and explicit CLI confirmation (`--yes` in automation).
|
|
291
|
+
|
|
292
|
+
### Reusable iframe configuration (4.11)
|
|
293
|
+
|
|
294
|
+
`flowbase iframes list|get|create|update|delete` manages environment-specific iframe drafts. Create/update use `--json-file`; fields are `label`, `icon` (default `IconWorld`), `color` (default `#2563EB`), and a complete HTTPS `url` without credentials. Update and delete require `baseRevision` from `iframes get`; deletion also requires confirmation (`--yes` for noninteractive use).
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
flowbase iframes create --json-file iframe.json
|
|
298
|
+
flowbase iframes get ifr_example
|
|
299
|
+
flowbase iframes update ifr_example --json-file iframe-update.json
|
|
300
|
+
flowbase apps add-iframes app_example ifr_example
|
|
301
|
+
flowbase apps set-iframe-group app_example ifr_example --group-id grp_example
|
|
302
|
+
flowbase apps set-iframe-group app_example ifr_example --ungrouped
|
|
303
|
+
flowbase apps reorder-members app_example --json '{"items":[{"type":"iframe","id":"ifr_example"}]}'
|
|
304
|
+
flowbase apps remove-iframe app_example ifr_example --yes
|
|
305
|
+
flowbase iframes delete ifr_example --json '{"baseRevision":12}' --yes
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
Removal only unlinks one app. Deletion unlinks all apps atomically. Changes follow the existing commit/release/rollback workflow; they do not fetch, proxy or modify the external website. API keys use `metadata:read`/`metadata:write`; browser roles use `iframe.manage` for shared resources and `app.manage` for app associations.
|
|
309
|
+
|
|
310
|
+
### Custom object views (4.12)
|
|
311
|
+
|
|
312
|
+
Read `flowbase docs catalogs custom-views` and `flowbase views list OBJECT` first. Save the following as `view.json`, replacing `baseRevision` with the current `draftRevision`:
|
|
313
|
+
|
|
314
|
+
```json
|
|
315
|
+
{
|
|
316
|
+
"baseRevision": 4,
|
|
317
|
+
"name": "Custom overview",
|
|
318
|
+
"enabled": false,
|
|
319
|
+
"defaultFieldIds": [],
|
|
320
|
+
"displayMode": "custom",
|
|
321
|
+
"custom": {
|
|
322
|
+
"runtimeVersion": "cv1",
|
|
323
|
+
"source": "import React from 'react'; export default function View(){return <div>Hello</div>}"
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
```bash
|
|
329
|
+
flowbase views create obj_example --json-file view.json
|
|
330
|
+
flowbase views list obj_example
|
|
331
|
+
flowbase views update obj_example viw_example --json-file view.json
|
|
332
|
+
flowbase views set-enabled obj_example viw_example --base-revision 6 --enabled --yes
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
Use the revision returned by the preceding write, rather than the example numbers. Custom views start disabled; preview in the browser and enable when ready. Updates replace the writable snapshot: preserve `custom.source`, `custom.runtimeVersion`, `displayMode`, filters and other configuration from `views list`, excluding the response-only `id` and `status`. Built-in/custom view types cannot be converted. JSX source is limited to 512 KiB UTF-8; the runtime supports `react`, `three` and `flowbase`. CLI configuration does not execute browser previews.
|
|
336
|
+
|
|
337
|
+
### Record detail embedded pages (4.13)
|
|
338
|
+
|
|
339
|
+
`flowbase docs catalogs page-components` documents `recordEmbed`, supported at the top level or inside tabs of a detail Page. Add this component to an existing region column (or a tab's `components`):
|
|
340
|
+
|
|
341
|
+
```json
|
|
342
|
+
{
|
|
343
|
+
"kind": "recordEmbed",
|
|
344
|
+
"label": "External panel",
|
|
345
|
+
"showTitle": true,
|
|
346
|
+
"url": "https://example.com/panel",
|
|
347
|
+
"height": 480,
|
|
348
|
+
"allowRead": false,
|
|
349
|
+
"allowedFieldIds": []
|
|
350
|
+
}
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
Read `flowbase pages get PAGE`, preserve the existing components and IDs, and remove the read-only Page keys listed in `docs catalogs page-components`. Wrap the editable snapshot as `{"baseRevision":4,"page":{...}}`, then use `flowbase pages update PAGE --json-file page.json` (or `pages create --json-file page.json` for a new detail Page). For creation, omit the Page ID and IDs of new regions/components so the server allocates them.
|
|
354
|
+
|
|
355
|
+
Height must be an integer from 240 to 1600. URLs must use external HTTPS and exclude credentials, identity/context parameters and templates. To permit SDK reads, set `allowRead: true` and select at least one unique active field ID in `allowedFieldIds`; current record/field permissions still apply. The browser SDK is `/sdk/record-embed.v1.js`. The CLI configures the component; rendering and SDK calls run in the browser. `flowbase-user` has no metadata management commands.
|
|
@@ -22,6 +22,42 @@ class Endpoint:
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
ENDPOINTS = (
|
|
25
|
+
Endpoint("iframes.list", "flowbase_iframes_list", "GET", "/iframes", "metadata:read", "List iframe configuration.", "flowbase iframes list", requires_confirmation=False, request_body=None),
|
|
26
|
+
Endpoint("iframes.get", "flowbase_iframes_get", "GET", "/iframes/{iframe_id}", "metadata:read", "Get iframe configuration.", "flowbase iframes get", requires_confirmation=False, request_body=None),
|
|
27
|
+
Endpoint("iframes.create", "flowbase_iframes_create", "POST", "/iframes", "metadata:write", "Create iframe configuration.", "flowbase iframes create", requires_confirmation=False, request_body='{"label": "Help", "url": "https://example.com", "icon": "IconWorld", "color": "#2563EB"}'),
|
|
28
|
+
Endpoint("iframes.update", "flowbase_iframes_update", "PUT", "/iframes/{iframe_id}", "metadata:write", "Update iframe configuration.", "flowbase iframes update", requires_confirmation=False, request_body='{"label": "Help", "url": "https://example.com", "icon": "IconWorld", "color": "#2563EB", "baseRevision": 0}'),
|
|
29
|
+
Endpoint("iframes.delete", "flowbase_iframes_delete", "POST", "/iframes/{iframe_id}/delete", "metadata:write", "Delete iframe configuration.", "flowbase iframes delete", requires_confirmation=True, request_body='{"baseRevision": 0}'),
|
|
30
|
+
Endpoint(
|
|
31
|
+
"apps.iframes.add",
|
|
32
|
+
"flowbase_apps_iframes_add",
|
|
33
|
+
"POST",
|
|
34
|
+
"/apps/{app_id}/iframes",
|
|
35
|
+
"metadata:write",
|
|
36
|
+
"Add iframes to an app (association only).",
|
|
37
|
+
"flowbase apps add-iframes app_xxx ifr_xxx",
|
|
38
|
+
request_body='{"iframeIds":["ifr_xxx"]}',
|
|
39
|
+
),
|
|
40
|
+
Endpoint(
|
|
41
|
+
"apps.iframes.remove",
|
|
42
|
+
"flowbase_apps_iframes_remove",
|
|
43
|
+
"DELETE",
|
|
44
|
+
"/apps/{app_id}/iframes/{iframe_id}",
|
|
45
|
+
"metadata:write",
|
|
46
|
+
"Remove a iframe association from an app.",
|
|
47
|
+
"flowbase apps remove-iframe app_xxx ifr_xxx --yes",
|
|
48
|
+
True,
|
|
49
|
+
),
|
|
50
|
+
Endpoint(
|
|
51
|
+
"apps.iframes.set-group",
|
|
52
|
+
"flowbase_apps_iframes_set_group",
|
|
53
|
+
"POST",
|
|
54
|
+
"/apps/{app_id}/iframes/{iframe_id}/group",
|
|
55
|
+
"metadata:write",
|
|
56
|
+
"Move an app-linked iframe into a group or ungroup it.",
|
|
57
|
+
"flowbase apps set-iframe-group app_xxx ifr_xxx --group-id grp_xxx",
|
|
58
|
+
request_body='{"groupId":"grp_xxx"}',
|
|
59
|
+
),
|
|
60
|
+
|
|
25
61
|
Endpoint('formulas.sources', 'flowbase_formulas_sources', 'GET', '/objects/{object_id}/formula/sources', 'metadata:read', 'Discover scalar formula sources in the draft.', 'flowbase formulas sources obj_xxx'),
|
|
26
62
|
Endpoint('formulas.collections', 'flowbase_formulas_collections', 'GET', '/objects/{object_id}/formula/collections', 'metadata:read', 'Discover collection object and field IDs in the draft.', 'flowbase formulas collections obj_xxx'),
|
|
27
63
|
Endpoint('formulas.validate', 'flowbase_formulas_validate', 'POST', '/objects/{object_id}/formula/validate', 'metadata:read', 'Validate formula or rollup; trial also supported. Requires records:read. No writes.', 'flowbase formulas validate obj_xxx --json-file formula.json', request_body='{"constraints":{"expression":"amount * 2","resultType":"number","scale":2},"samples":{"amount":12.50},"trial":true}'),
|
|
@@ -258,7 +294,7 @@ ENDPOINTS = (
|
|
|
258
294
|
'{"fieldId":"fld_done","operator":"is_true"}'
|
|
259
295
|
'],"defaultFieldIds":["fld_a","fld_b"],"groupFieldId":null,"displayMode":"table","parentFieldId":null,"gantt":{}}'
|
|
260
296
|
)),
|
|
261
|
-
Endpoint("views.update", "flowbase_views_update", "PUT", "/objects/{object_id}/views/{view_id}", "metadata:write", "Update a complete view snapshot. Preserve displayMode, parentFieldId and
|
|
297
|
+
Endpoint("views.update", "flowbase_views_update", "PUT", "/objects/{object_id}/views/{view_id}", "metadata:write", "Update a complete view snapshot. Preserve displayMode, parentFieldId, gantt and custom from views.list; Read custom-views catalog for JSX configuration; omitted fields use defaults.", "flowbase views update obj_xxx viw_xxx --json-file view.json",
|
|
262
298
|
request_body=(
|
|
263
299
|
'{"baseRevision":4,"name":"Active","enabled":true,"match":"all",'
|
|
264
300
|
'"filters":['
|
|
@@ -1040,7 +1076,7 @@ APPROVAL_NODE_TYPES = (
|
|
|
1040
1076
|
)
|
|
1041
1077
|
|
|
1042
1078
|
FUNCTION_PERMISSIONS = (
|
|
1043
|
-
"workspace.access", "app.manage", "object.manage", "dashboard.manage", "form.manage",
|
|
1079
|
+
"workspace.access", "app.manage", "object.manage", "dashboard.manage", "form.manage", "iframe.manage",
|
|
1044
1080
|
"version.manage", "org.manage", "system.manage",
|
|
1045
1081
|
)
|
|
1046
1082
|
|
|
@@ -1088,7 +1124,7 @@ PAGE_COMPONENTS = {
|
|
|
1088
1124
|
),
|
|
1089
1125
|
"detailOnlyKinds": (
|
|
1090
1126
|
"relatedList", "approval", "detailSummary", "stageBar", "tabs",
|
|
1091
|
-
"relatedSummary", "attachmentCard", "noticeBlock",
|
|
1127
|
+
"relatedSummary", "attachmentCard", "noticeBlock", "recordEmbed",
|
|
1092
1128
|
),
|
|
1093
1129
|
},
|
|
1094
1130
|
"kinds": (
|
|
@@ -1207,7 +1243,7 @@ PAGE_COMPONENTS = {
|
|
|
1207
1243
|
"minimumComponents": 1,
|
|
1208
1244
|
"allowedChildKinds": (
|
|
1209
1245
|
"field", "relatedList", "approval", "stageBar",
|
|
1210
|
-
"relatedSummary", "attachmentCard", "noticeBlock",
|
|
1246
|
+
"relatedSummary", "attachmentCard", "noticeBlock", "recordEmbed",
|
|
1211
1247
|
),
|
|
1212
1248
|
},
|
|
1213
1249
|
"note": "defaultTabId must reference a tab in this component; tabs cannot be nested.",
|
|
@@ -1248,6 +1284,22 @@ PAGE_COMPONENTS = {
|
|
|
1248
1284
|
"titleLengthWhenShown": (1, 50),
|
|
1249
1285
|
},
|
|
1250
1286
|
},
|
|
1287
|
+
{
|
|
1288
|
+
"kind": "recordEmbed",
|
|
1289
|
+
"name": "record detail embedded page",
|
|
1290
|
+
"pageTypes": ("detail",),
|
|
1291
|
+
"placement": ("topLevel", "tabs"),
|
|
1292
|
+
"requiredKeys": ("kind", "label", "url"),
|
|
1293
|
+
"optionalKeys": ("id", "showTitle", "height", "allowRead", "allowedFieldIds"),
|
|
1294
|
+
"defaults": {"showTitle": True, "height": 480, "allowRead": False, "allowedFieldIds": []},
|
|
1295
|
+
"constraints": {
|
|
1296
|
+
"labelLength": (1, 80),
|
|
1297
|
+
"height": "integer, 240–1600",
|
|
1298
|
+
"url": "External HTTPS only; no credentials, identity/context parameters, templates, localhost or FlowBase hosts.",
|
|
1299
|
+
"allowedFieldIds": "Unique active field IDs on the Page object; at least one when allowRead=true. Runtime reads also enforce current record and field permissions.",
|
|
1300
|
+
},
|
|
1301
|
+
"runtime": "Browser SDK /sdk/record-embed.v1.js; read-only bridge. CLI authors configuration and does not render or execute the embed.",
|
|
1302
|
+
},
|
|
1251
1303
|
{
|
|
1252
1304
|
"kind": "noticeBlock",
|
|
1253
1305
|
"name": "notice block",
|
|
@@ -1323,7 +1375,7 @@ PAGE_RULES = {
|
|
|
1323
1375
|
"states": ("visible", "hidden"),
|
|
1324
1376
|
"targetKinds": (
|
|
1325
1377
|
"relatedList", "approval", "detailSummary", "stageBar", "tabs",
|
|
1326
|
-
"relatedSummary", "attachmentCard", "noticeBlock",
|
|
1378
|
+
"relatedSummary", "attachmentCard", "noticeBlock", "recordEmbed",
|
|
1327
1379
|
),
|
|
1328
1380
|
"excludedTargets": ("field", "region", "tab", "button", "systemArea"),
|
|
1329
1381
|
"sameRuleUniqueTarget": True,
|
|
@@ -1542,6 +1594,13 @@ FORMS = {
|
|
|
1542
1594
|
}
|
|
1543
1595
|
|
|
1544
1596
|
CATALOGS = {
|
|
1597
|
+
"custom-views": {
|
|
1598
|
+
"commands": "views list/create/update/set-enabled/delete; create/update accept --json-file.",
|
|
1599
|
+
"example": {"baseRevision": 4, "name": "Custom", "enabled": False, "defaultFieldIds": [], "displayMode": "custom", "custom": {"runtimeVersion": "cv1", "source": "import React from 'react'; export default function View(){return <div>Hello</div>}"}},
|
|
1600
|
+
"update": "Read views.list; preserve custom.source, custom.runtimeVersion, displayMode and the other writable snapshot fields. Use draftRevision as baseRevision; omit response-only id and status from the body.",
|
|
1601
|
+
"constraints": "Custom views start disabled; enable separately after validation. Built-in and custom views cannot convert into each other. custom contains exactly source and runtimeVersion=cv1; source must be nonempty and at most 512 KiB UTF-8.",
|
|
1602
|
+
"runtime": "Sandboxed browser JSX, with react/three/flowbase imports. CLI saves configuration; browser preview/read bridge is not exposed as an API-key CLI command.",
|
|
1603
|
+
},
|
|
1545
1604
|
"planning": {
|
|
1546
1605
|
"viewUpdate": "Read views.list, preserve the complete snapshot, then views.update with baseRevision. Omitting displayMode/parentFieldId/gantt resets them to table/null/{}.",
|
|
1547
1606
|
"tree": {"displayMode": "tree", "parentFieldId": "fld_parent", "gantt": {}},
|
|
@@ -467,6 +467,35 @@ def handle_apps(args: argparse.Namespace) -> int:
|
|
|
467
467
|
path_params={"app_id": args.app_id, "dashboard_id": args.dashboard_id},
|
|
468
468
|
body=body,
|
|
469
469
|
)
|
|
470
|
+
if action == "add-iframes":
|
|
471
|
+
ids = [item.strip() for item in args.iframe_ids if item.strip()]
|
|
472
|
+
if not ids:
|
|
473
|
+
raise CliError("Provide at least one iframe ID.")
|
|
474
|
+
return run_request(
|
|
475
|
+
args,
|
|
476
|
+
"apps.iframes.add",
|
|
477
|
+
path_params={"app_id": args.app_id},
|
|
478
|
+
body={"iframeIds": ids},
|
|
479
|
+
)
|
|
480
|
+
if action == "remove-iframe":
|
|
481
|
+
return run_request(
|
|
482
|
+
args,
|
|
483
|
+
"apps.iframes.remove",
|
|
484
|
+
path_params={"app_id": args.app_id, "iframe_id": args.iframe_id},
|
|
485
|
+
)
|
|
486
|
+
if action == "set-iframe-group":
|
|
487
|
+
if args.ungrouped:
|
|
488
|
+
body = {"groupId": None}
|
|
489
|
+
elif args.group_id is not None:
|
|
490
|
+
body = {"groupId": args.group_id}
|
|
491
|
+
else:
|
|
492
|
+
raise CliError("Provide --group-id or --ungrouped.")
|
|
493
|
+
return run_request(
|
|
494
|
+
args,
|
|
495
|
+
"apps.iframes.set-group",
|
|
496
|
+
path_params={"app_id": args.app_id, "iframe_id": args.iframe_id},
|
|
497
|
+
body=body,
|
|
498
|
+
)
|
|
470
499
|
if action == "reorder-members":
|
|
471
500
|
body = _payload_from_args(args, {}, ("items",))
|
|
472
501
|
if not isinstance(body["items"], list):
|
|
@@ -522,6 +551,13 @@ def handle_dashboards(args: argparse.Namespace) -> int:
|
|
|
522
551
|
)
|
|
523
552
|
|
|
524
553
|
|
|
554
|
+
def handle_iframes(args: argparse.Namespace) -> int:
|
|
555
|
+
action = args.iframes_action
|
|
556
|
+
params = {"iframe_id": args.iframe_id} if action in ("get", "update", "delete") else None
|
|
557
|
+
body = load_json_payload(args.json, args.json_file) if action in ("create", "update", "delete") else None
|
|
558
|
+
return run_request(args, f"iframes.{action}", path_params=params, body=body)
|
|
559
|
+
|
|
560
|
+
|
|
525
561
|
def handle_forms(args: argparse.Namespace) -> int:
|
|
526
562
|
action = args.forms_action
|
|
527
563
|
if action == "list":
|
|
@@ -1162,6 +1198,26 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
1162
1198
|
action="store_true",
|
|
1163
1199
|
help="Remove the dashboard from its current group in this app.",
|
|
1164
1200
|
)
|
|
1201
|
+
app_add_iframes = app_actions.add_parser("add-iframes")
|
|
1202
|
+
app_add_iframes.add_argument("app_id")
|
|
1203
|
+
app_add_iframes.add_argument(
|
|
1204
|
+
"iframe_ids",
|
|
1205
|
+
nargs="+",
|
|
1206
|
+
help="One or more iframe IDs to associate with the app.",
|
|
1207
|
+
)
|
|
1208
|
+
app_remove_iframe = app_actions.add_parser("remove-iframe")
|
|
1209
|
+
app_remove_iframe.add_argument("app_id")
|
|
1210
|
+
app_remove_iframe.add_argument("iframe_id")
|
|
1211
|
+
add_yes(app_remove_iframe)
|
|
1212
|
+
app_set_iframe_group = app_actions.add_parser("set-iframe-group")
|
|
1213
|
+
app_set_iframe_group.add_argument("app_id")
|
|
1214
|
+
app_set_iframe_group.add_argument("iframe_id")
|
|
1215
|
+
app_set_iframe_group.add_argument("--group-id", help="Target group ID. Omit with --ungrouped.")
|
|
1216
|
+
app_set_iframe_group.add_argument(
|
|
1217
|
+
"--ungrouped",
|
|
1218
|
+
action="store_true",
|
|
1219
|
+
help="Remove the iframe from its current group in this app.",
|
|
1220
|
+
)
|
|
1165
1221
|
app_reorder_members = app_actions.add_parser("reorder-members")
|
|
1166
1222
|
app_reorder_members.add_argument("app_id")
|
|
1167
1223
|
add_json_args(app_reorder_members, endpoint_key="apps.members.reorder")
|
|
@@ -1192,6 +1248,18 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
1192
1248
|
add_yes(dashboard_delete)
|
|
1193
1249
|
dashboards.set_defaults(handler=handle_dashboards)
|
|
1194
1250
|
|
|
1251
|
+
iframes = groups.add_parser("iframes", help="Manage reusable iframe configurations.")
|
|
1252
|
+
iframe_actions = iframes.add_subparsers(dest="iframes_action", required=True)
|
|
1253
|
+
for action in ("list", "get", "create", "update", "delete"):
|
|
1254
|
+
command = iframe_actions.add_parser(action)
|
|
1255
|
+
if action in ("get", "update", "delete"):
|
|
1256
|
+
command.add_argument("iframe_id")
|
|
1257
|
+
if action in ("create", "update", "delete"):
|
|
1258
|
+
add_json_args(command, endpoint_key=f"iframes.{action}")
|
|
1259
|
+
if action == "delete":
|
|
1260
|
+
add_yes(command)
|
|
1261
|
+
iframes.set_defaults(handler=handle_iframes)
|
|
1262
|
+
|
|
1195
1263
|
forms = groups.add_parser("forms", help="Manage custom forms (public collection links).")
|
|
1196
1264
|
form_actions = forms.add_subparsers(dest="forms_action", required=True)
|
|
1197
1265
|
form_actions.add_parser("list")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flowbase-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.16
|
|
4
4
|
Summary: Command line client for the FlowBase OpenAPI
|
|
5
5
|
Author: DeepFlowAI
|
|
6
6
|
License: Apache-2.0
|
|
@@ -160,6 +160,14 @@ flowbase objects cli-edit-policy update obj_xxx --json '{"baseRevision":4,"polic
|
|
|
160
160
|
|
|
161
161
|
`records create` returns `{recordId}`; use it with `records get`.
|
|
162
162
|
|
|
163
|
+
To add existing objects to an application, pass their IDs with `--object-ids`:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
flowbase apps add-objects app_xxx --object-ids obj_a,obj_b
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Use a comma-separated list for multiple objects. Object IDs are not positional arguments. Run `flowbase docs show apps.objects.add` for the endpoint details.
|
|
170
|
+
|
|
163
171
|
Record `values` keys are **field keys** (`name`), not internal IDs (`fld_...`). IDs are `obj_`/`fld_`/`dsh_`/`wfl_`/`pag_`/`reg_`/`cmp_`-prefixed; see `docs catalogs id-prefixes`.
|
|
164
172
|
|
|
165
173
|
### 6.2 Edit and publish configuration on a test environment
|
|
@@ -289,3 +297,68 @@ Transport requests time out after 60 seconds. A lost write response has an unkno
|
|
|
289
297
|
- `flowbase docs catalogs workflow-python`: record creation examples and failed-task retry. `workflows python-runtime OBJECT new` discovers current object bindings; `workflows executions` includes Python attempts, logs and `canRetry`.
|
|
290
298
|
|
|
291
299
|
Use `records list OBJECT --view-id VIEW --view-layout` for tree/Gantt projections; the default remains a flat list. `records update` accepts `updatedAt` and `planViewId` in its JSON body for version-checked plan edits. Formula validation/trials require both metadata read and record read; workflow retry requires both metadata write and record write and explicit CLI confirmation (`--yes` in automation).
|
|
300
|
+
|
|
301
|
+
### Reusable iframe configuration (4.11)
|
|
302
|
+
|
|
303
|
+
`flowbase iframes list|get|create|update|delete` manages environment-specific iframe drafts. Create/update use `--json-file`; fields are `label`, `icon` (default `IconWorld`), `color` (default `#2563EB`), and a complete HTTPS `url` without credentials. Update and delete require `baseRevision` from `iframes get`; deletion also requires confirmation (`--yes` for noninteractive use).
|
|
304
|
+
|
|
305
|
+
```bash
|
|
306
|
+
flowbase iframes create --json-file iframe.json
|
|
307
|
+
flowbase iframes get ifr_example
|
|
308
|
+
flowbase iframes update ifr_example --json-file iframe-update.json
|
|
309
|
+
flowbase apps add-iframes app_example ifr_example
|
|
310
|
+
flowbase apps set-iframe-group app_example ifr_example --group-id grp_example
|
|
311
|
+
flowbase apps set-iframe-group app_example ifr_example --ungrouped
|
|
312
|
+
flowbase apps reorder-members app_example --json '{"items":[{"type":"iframe","id":"ifr_example"}]}'
|
|
313
|
+
flowbase apps remove-iframe app_example ifr_example --yes
|
|
314
|
+
flowbase iframes delete ifr_example --json '{"baseRevision":12}' --yes
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
Removal only unlinks one app. Deletion unlinks all apps atomically. Changes follow the existing commit/release/rollback workflow; they do not fetch, proxy or modify the external website. API keys use `metadata:read`/`metadata:write`; browser roles use `iframe.manage` for shared resources and `app.manage` for app associations.
|
|
318
|
+
|
|
319
|
+
### Custom object views (4.12)
|
|
320
|
+
|
|
321
|
+
Read `flowbase docs catalogs custom-views` and `flowbase views list OBJECT` first. Save the following as `view.json`, replacing `baseRevision` with the current `draftRevision`:
|
|
322
|
+
|
|
323
|
+
```json
|
|
324
|
+
{
|
|
325
|
+
"baseRevision": 4,
|
|
326
|
+
"name": "Custom overview",
|
|
327
|
+
"enabled": false,
|
|
328
|
+
"defaultFieldIds": [],
|
|
329
|
+
"displayMode": "custom",
|
|
330
|
+
"custom": {
|
|
331
|
+
"runtimeVersion": "cv1",
|
|
332
|
+
"source": "import React from 'react'; export default function View(){return <div>Hello</div>}"
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
```bash
|
|
338
|
+
flowbase views create obj_example --json-file view.json
|
|
339
|
+
flowbase views list obj_example
|
|
340
|
+
flowbase views update obj_example viw_example --json-file view.json
|
|
341
|
+
flowbase views set-enabled obj_example viw_example --base-revision 6 --enabled --yes
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Use the revision returned by the preceding write, rather than the example numbers. Custom views start disabled; preview in the browser and enable when ready. Updates replace the writable snapshot: preserve `custom.source`, `custom.runtimeVersion`, `displayMode`, filters and other configuration from `views list`, excluding the response-only `id` and `status`. Built-in/custom view types cannot be converted. JSX source is limited to 512 KiB UTF-8; the runtime supports `react`, `three` and `flowbase`. CLI configuration does not execute browser previews.
|
|
345
|
+
|
|
346
|
+
### Record detail embedded pages (4.13)
|
|
347
|
+
|
|
348
|
+
`flowbase docs catalogs page-components` documents `recordEmbed`, supported at the top level or inside tabs of a detail Page. Add this component to an existing region column (or a tab's `components`):
|
|
349
|
+
|
|
350
|
+
```json
|
|
351
|
+
{
|
|
352
|
+
"kind": "recordEmbed",
|
|
353
|
+
"label": "External panel",
|
|
354
|
+
"showTitle": true,
|
|
355
|
+
"url": "https://example.com/panel",
|
|
356
|
+
"height": 480,
|
|
357
|
+
"allowRead": false,
|
|
358
|
+
"allowedFieldIds": []
|
|
359
|
+
}
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
Read `flowbase pages get PAGE`, preserve the existing components and IDs, and remove the read-only Page keys listed in `docs catalogs page-components`. Wrap the editable snapshot as `{"baseRevision":4,"page":{...}}`, then use `flowbase pages update PAGE --json-file page.json` (or `pages create --json-file page.json` for a new detail Page). For creation, omit the Page ID and IDs of new regions/components so the server allocates them.
|
|
363
|
+
|
|
364
|
+
Height must be an integer from 240 to 1600. URLs must use external HTTPS and exclude credentials, identity/context parameters and templates. To permit SDK reads, set `allowRead: true` and select at least one unique active field ID in `allowedFieldIds`; current record/field permissions still apply. The browser SDK is `/sdk/record-embed.v1.js`. The CLI configures the component; rendering and SDK calls run in the browser. `flowbase-user` has no metadata management commands.
|
|
@@ -261,7 +261,7 @@ class FlowBaseCliTest(unittest.TestCase):
|
|
|
261
261
|
kinds = {item.get("kind") for item in page_components["kinds"]}
|
|
262
262
|
self.assertEqual(kinds, {
|
|
263
263
|
None, "relatedList", "approval", "detailSummary", "stageBar",
|
|
264
|
-
"tabs", "relatedSummary", "attachmentCard", "noticeBlock",
|
|
264
|
+
"tabs", "relatedSummary", "attachmentCard", "noticeBlock", "recordEmbed",
|
|
265
265
|
})
|
|
266
266
|
approval = next(
|
|
267
267
|
item for item in page_components["kinds"] if item.get("kind") == "approval"
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Iframe CLI uses the same API contracts as browser management."""
|
|
2
|
+
import io
|
|
3
|
+
from unittest.mock import patch
|
|
4
|
+
import pytest
|
|
5
|
+
from flowbase_cli.main import main
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@pytest.mark.parametrize("args,endpoint,path,body", [
|
|
9
|
+
(["iframes", "list"], "iframes.list", None, None),
|
|
10
|
+
(["iframes", "get", "ifr_x"], "iframes.get", {"iframe_id": "ifr_x"}, None),
|
|
11
|
+
(["iframes", "create", "--json", '{"label":"Help","url":"https://example.com"}'], "iframes.create", None, {"label":"Help","url":"https://example.com"}),
|
|
12
|
+
(["iframes", "update", "ifr_x", "--json", '{"label":"Help","url":"https://example.com","baseRevision":3}'], "iframes.update", {"iframe_id":"ifr_x"}, {"label":"Help","url":"https://example.com","baseRevision":3}),
|
|
13
|
+
(["iframes", "delete", "ifr_x", "--yes", "--json", '{"baseRevision":4}'], "iframes.delete", {"iframe_id":"ifr_x"}, {"baseRevision":4}),
|
|
14
|
+
(["apps", "add-iframes", "app_x", "ifr_x", "ifr_y"], "apps.iframes.add", {"app_id":"app_x"}, {"iframeIds":["ifr_x","ifr_y"]}),
|
|
15
|
+
(["apps", "remove-iframe", "app_x", "ifr_x", "--yes"], "apps.iframes.remove", {"app_id":"app_x","iframe_id":"ifr_x"}, None),
|
|
16
|
+
(["apps", "set-iframe-group", "app_x", "ifr_x", "--ungrouped"], "apps.iframes.set-group", {"app_id":"app_x","iframe_id":"ifr_x"}, {"groupId":None}),
|
|
17
|
+
(["apps", "reorder-members", "app_x", "--json", '{"items":[{"type":"iframe","id":"ifr_x"}]}'], "apps.members.reorder", {"app_id":"app_x"}, {"items":[{"type":"iframe","id":"ifr_x"}]}),
|
|
18
|
+
])
|
|
19
|
+
def test_iframe_cli_request(args, endpoint, path, body):
|
|
20
|
+
with patch("flowbase_cli.main.OpenApiClient.request", return_value=b"{}") as request, patch("sys.stdout", io.StringIO()):
|
|
21
|
+
assert main(args) == 0
|
|
22
|
+
assert request.call_args.args[0] == endpoint
|
|
23
|
+
assert request.call_args.kwargs["path_params"] == path
|
|
24
|
+
assert request.call_args.kwargs["body"] == body
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_delete_requires_confirmation():
|
|
28
|
+
with patch("flowbase_cli.main.OpenApiClient.request") as request, patch("sys.stdin.isatty", return_value=False), patch("sys.stderr", io.StringIO()):
|
|
29
|
+
assert main(["iframes", "delete", "ifr_x", "--json", '{"baseRevision":0}']) == 1
|
|
30
|
+
request.assert_not_called()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|