projects()
Returns the workflow project list of an organisation via wfm.GetProjectList.
|
The response is a flat list: it carries no parent attribute and no nesting. No server job
returns the project hierarchy as an output parameter — it is only available from the
|
1. Signature
-
Sync
-
Async
ecm.workflow.projects(
organisation: str | ECMOrganisation | None = None,
) -> list[ECMWorkflowProject]
await ecm.workflow.projects(
organisation: str | ECMOrganisation | None = None,
) -> list[ECMWorkflowProject]
2. Parameters
| Parameter | Type | Description |
|---|---|---|
|
|
The organisation as a GUID or as an |
3. Return value
A list of ECMWorkflowProject instances in server order. Returns an empty list when the
organisation holds no projects.
3.1. ECMWorkflowProject fields
| Field | Type | Description |
|---|---|---|
|
|
GUID of the project. |
|
|
Display name. The system project is named |
|
|
|
|
|
GUID of the creator, empty for entries the server created itself. |
|
|
Creation time as a UTC |
|
|
Description, empty when unset. |
3.2. ECMWorkflowProjectType values
| Member | Value | Meaning |
|---|---|---|
|
|
The organisation’s single root project; every other project hangs below it. |
|
|
An ordinary workflow project — a folder grouping projects and families. |
|
|
A workflow family. Its models are listed by the server job |
4. Examples
4.1. List the projects
-
Sync
-
Async
for project in ecm.workflow.projects():
print(f"{project.type.name:8} {project.name} ({project.id})")
for project in await ecm.workflow.projects():
print(f"{project.type.name:8} {project.name} ({project.id})")
4.2. Find the root project
The root project is the entry point for a full export, and its name makes a good name for the target folder.
-
Sync
-
Async
from ecmind_blue_client.ecm import ECMWorkflowProjectType
root = next(p for p in ecm.workflow.projects() if p.type is ECMWorkflowProjectType.ROOT)
print(root.name)
from ecmind_blue_client.ecm import ECMWorkflowProjectType
projects = await ecm.workflow.projects()
root = next(p for p in projects if p.type is ECMWorkflowProjectType.ROOT)
print(root.name)
5. Reconstructing the project hierarchy
No server job returns the edges of the tree as an output parameter. That holds for every
documented wfm job and for every other namespace. From the job outputs alone, only the
nodes and their type (this job) and the model-to-family edge (wfm.GetWorkflowList via
FamilyId) can be derived.
The documentation is asymmetric here: wfm.Export and wfm.Import require the hierarchy
as input (WFProjectTree nested, DestPrjId, OldParent), but no job hands it back.
|
Two tempting false leads:
|
5.1. Route 1: edges from oswfprojectsrel
rows = ecm.db.select(
"SELECT parent_id, project_id FROM oswfprojectsrel WHERE org_id = %s",
organisation_id,
)
parent_of = {row.typed("project_id", str): row.typed("parent_id", str) for row in rows}
Prerequisites and pitfalls:
-
System role
88("Server: Execute Ado jobs") is required, otherwiseado.ExecuteSQLfails — with an untypedBlueException, because there is no error translation for ADO result codes. -
ado.ExecuteSQLbypasses the DMS permission check, andimpersonate()has no effect on it: the context switch is a job parameter, not a database context. -
The
org_idfilter is mandatory — the table holds every organisation. -
The schema page of the reference carries the note that it was generated automatically and may be incomplete or incorrect. A server upgrade can change the table without the API changing.
5.2. Route 2: read it from the export file
wfm.Export returns the projects natively nested, so the hierarchy is already in the
file an export produces anyway — no SQL and no extra rights. Structure and example code are
in export().
|
The format of the export file is described in no edition of the server reference, and there
is no XSD for it. Reading it is reverse engineering without a compatibility guarantee.
Measured against enaio 12.0, the edges read from it match |
5.3. Invariants for assembling the tree
Measured on enaio 12.0 and valid on both installations checked:
-
Exactly one project has
type is ECMWorkflowProjectType.ROOT, and only that one has no parent row. -
The edges form a tree: for
nprojects there aren-1edges, and each project is the target of at most one edge. -
Workflow models hang below
FAMILYonly, and families never have sub-projects. The tree is therefore root → projects → family → models. -
Project names are not unique. On one of the test systems a project and a family are both named
test. Anyone building directories from them has to handle collisions.
5.4. Why the client does not do this for you
ecm.workflow mirrors the server API rather than extending it with queries against the
database schema. A public operation issuing SQL internally would silently require system
role 88, bypass the permission check and the effect of impersonate(), and couple the
client to a schema with no compatibility guarantee. The call therefore stays with the
caller, who knows the cost and decides.
6. See also
-
export()— export the organisation and its projects -
organisations()— list the organisations -
ecm.db.select()— free SQL