Add template and generated artifact contracts
This commit is contained in:
@@ -0,0 +1,28 @@
|
|||||||
|
# Template And Generated Artifact Capability Contracts
|
||||||
|
|
||||||
|
Core defines provider-neutral contracts for optional template libraries and
|
||||||
|
generated artifact storage. Core does not render templates or store generated
|
||||||
|
files itself.
|
||||||
|
|
||||||
|
## Templates
|
||||||
|
|
||||||
|
- `templates.catalog` lists typed, versioned template references and checks a
|
||||||
|
consumer's available fields, usage, and output format.
|
||||||
|
- `templates.renderer` accepts a `TemplateRenderRequest` containing pinned
|
||||||
|
input data and returns immutable render evidence plus an artifact reference.
|
||||||
|
|
||||||
|
The DTOs contain identifiers, hashes, plain mappings, and scalar metadata. They
|
||||||
|
do not expose Template ORM models or require Campaign, Distribution Lists,
|
||||||
|
Addresses, Reporting, Forms, or Mail.
|
||||||
|
|
||||||
|
## Generated Artifacts
|
||||||
|
|
||||||
|
`files.artifact_store` accepts a `ManagedArtifactWriteRequest` and returns a
|
||||||
|
`ManagedArtifactRef`. Producers supply bytes, a safe filename/content type,
|
||||||
|
idempotency key, and non-secret provenance. Files owns path normalization,
|
||||||
|
authorization, versions, storage, and download behavior.
|
||||||
|
|
||||||
|
Consumers must discover both contracts through the module registry and degrade
|
||||||
|
only the unavailable path. A template renderer may return a bounded download
|
||||||
|
when Files is absent. A caller must not infer successful external delivery from
|
||||||
|
successful rendering or artifact persistence.
|
||||||
@@ -1,13 +1,52 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from collections.abc import Mapping
|
||||||
|
from dataclasses import dataclass, field
|
||||||
from typing import Protocol, runtime_checkable
|
from typing import Protocol, runtime_checkable
|
||||||
|
|
||||||
from govoplan_core.core.access import ResourceAccessExplanationProvider
|
from govoplan_core.core.access import ResourceAccessExplanationProvider
|
||||||
|
|
||||||
|
|
||||||
CAPABILITY_FILES_ACCESS = "files.access"
|
CAPABILITY_FILES_ACCESS = "files.access"
|
||||||
|
CAPABILITY_FILES_ARTIFACT_STORE = "files.artifact_store"
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True, slots=True)
|
||||||
|
class ManagedArtifactWriteRequest:
|
||||||
|
filename: str
|
||||||
|
payload: bytes
|
||||||
|
content_type: str
|
||||||
|
folder: str = "Generated"
|
||||||
|
description: str | None = None
|
||||||
|
idempotency_key: str | None = None
|
||||||
|
metadata: Mapping[str, object] = field(default_factory=dict)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True, slots=True)
|
||||||
|
class ManagedArtifactRef:
|
||||||
|
file_asset_id: str
|
||||||
|
file_version_id: str
|
||||||
|
filename: str
|
||||||
|
display_path: str
|
||||||
|
content_type: str
|
||||||
|
size_bytes: int
|
||||||
|
sha256: str
|
||||||
|
provenance: Mapping[str, object] = field(default_factory=dict)
|
||||||
|
|
||||||
|
|
||||||
@runtime_checkable
|
@runtime_checkable
|
||||||
class FileAccessProvider(ResourceAccessExplanationProvider, Protocol):
|
class FileAccessProvider(ResourceAccessExplanationProvider, Protocol):
|
||||||
"""Resource-level access explanation provider for Files-owned resources."""
|
"""Resource-level access explanation provider for Files-owned resources."""
|
||||||
|
|
||||||
|
|
||||||
|
@runtime_checkable
|
||||||
|
class ManagedArtifactStore(Protocol):
|
||||||
|
"""Store generated module artifacts without exposing Files internals."""
|
||||||
|
|
||||||
|
def store_artifact(
|
||||||
|
self,
|
||||||
|
session: object,
|
||||||
|
principal: object,
|
||||||
|
*,
|
||||||
|
request: ManagedArtifactWriteRequest,
|
||||||
|
) -> ManagedArtifactRef: ...
|
||||||
|
|||||||
@@ -0,0 +1,236 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from collections.abc import Mapping, Sequence
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
from datetime import datetime
|
||||||
|
from typing import Literal, Protocol, runtime_checkable
|
||||||
|
|
||||||
|
|
||||||
|
CAPABILITY_TEMPLATE_CATALOG = "templates.catalog"
|
||||||
|
CAPABILITY_TEMPLATE_RENDERER = "templates.renderer"
|
||||||
|
|
||||||
|
TemplateType = Literal[
|
||||||
|
"label",
|
||||||
|
"label_sheet",
|
||||||
|
"envelope",
|
||||||
|
"serial_letter",
|
||||||
|
"form_letter",
|
||||||
|
"list_layout",
|
||||||
|
"email",
|
||||||
|
"generic",
|
||||||
|
]
|
||||||
|
TemplateOutputFormat = Literal["html", "text"]
|
||||||
|
TemplateRenderMode = Literal["preview", "final"]
|
||||||
|
|
||||||
|
|
||||||
|
class TemplateContractError(ValueError):
|
||||||
|
"""Stable base error for provider-neutral template operations."""
|
||||||
|
|
||||||
|
|
||||||
|
class TemplateNotFoundError(TemplateContractError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class TemplateCompatibilityError(TemplateContractError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class TemplateRenderError(TemplateContractError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True, slots=True)
|
||||||
|
class TemplateFieldRequirement:
|
||||||
|
path: str
|
||||||
|
value_type: Literal[
|
||||||
|
"string",
|
||||||
|
"integer",
|
||||||
|
"number",
|
||||||
|
"boolean",
|
||||||
|
"date",
|
||||||
|
"datetime",
|
||||||
|
"object",
|
||||||
|
"array",
|
||||||
|
] = "string"
|
||||||
|
label: str | None = None
|
||||||
|
required: bool = True
|
||||||
|
description: str | None = None
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True, slots=True)
|
||||||
|
class TemplateOutputProfile:
|
||||||
|
id: str
|
||||||
|
label: str
|
||||||
|
output_format: TemplateOutputFormat
|
||||||
|
media_type: str
|
||||||
|
channel: str = "print"
|
||||||
|
capabilities: tuple[str, ...] = ()
|
||||||
|
page: Mapping[str, object] = field(default_factory=dict)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True, slots=True)
|
||||||
|
class TemplateRevisionRef:
|
||||||
|
id: str
|
||||||
|
template_id: str
|
||||||
|
revision: int
|
||||||
|
definition_hash: str
|
||||||
|
template_type: TemplateType
|
||||||
|
usages: tuple[str, ...]
|
||||||
|
locale: str
|
||||||
|
required_fields: tuple[TemplateFieldRequirement, ...]
|
||||||
|
output_profiles: tuple[TemplateOutputProfile, ...]
|
||||||
|
published_at: datetime | None = None
|
||||||
|
provenance: Mapping[str, object] = field(default_factory=dict)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True, slots=True)
|
||||||
|
class TemplateRef:
|
||||||
|
id: str
|
||||||
|
tenant_id: str
|
||||||
|
name: str
|
||||||
|
slug: str
|
||||||
|
template_type: TemplateType
|
||||||
|
status: str
|
||||||
|
current_revision: int
|
||||||
|
current_revision_id: str
|
||||||
|
published_revision_id: str | None
|
||||||
|
description: str | None = None
|
||||||
|
scope_type: str = "tenant"
|
||||||
|
scope_id: str | None = None
|
||||||
|
read_only: bool = False
|
||||||
|
updated_at: datetime | None = None
|
||||||
|
revision: TemplateRevisionRef | None = None
|
||||||
|
metadata: Mapping[str, object] = field(default_factory=dict)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True, slots=True)
|
||||||
|
class TemplateCompatibility:
|
||||||
|
compatible: bool
|
||||||
|
template_id: str
|
||||||
|
revision_id: str
|
||||||
|
usage: str | None
|
||||||
|
output_format: str | None
|
||||||
|
missing_fields: tuple[str, ...] = ()
|
||||||
|
incompatible_fields: tuple[str, ...] = ()
|
||||||
|
diagnostics: tuple[Mapping[str, object], ...] = ()
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True, slots=True)
|
||||||
|
class TemplateRenderRequest:
|
||||||
|
template_id: str
|
||||||
|
revision: int | None = None
|
||||||
|
usage: str | None = None
|
||||||
|
locale: str | None = None
|
||||||
|
output_format: TemplateOutputFormat = "html"
|
||||||
|
profile_id: str | None = None
|
||||||
|
parameters: Mapping[str, object] = field(default_factory=dict)
|
||||||
|
items: tuple[Mapping[str, object], ...] = ()
|
||||||
|
input_snapshot: Mapping[str, object] = field(default_factory=dict)
|
||||||
|
mode: TemplateRenderMode = "preview"
|
||||||
|
idempotency_key: str | None = None
|
||||||
|
persist_to_files: bool = False
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True, slots=True)
|
||||||
|
class TemplateArtifactRef:
|
||||||
|
kind: Literal["managed_file", "bounded_download"]
|
||||||
|
filename: str
|
||||||
|
content_type: str
|
||||||
|
size_bytes: int
|
||||||
|
sha256: str
|
||||||
|
file_asset_id: str | None = None
|
||||||
|
file_version_id: str | None = None
|
||||||
|
download_path: str | None = None
|
||||||
|
provenance: Mapping[str, object] = field(default_factory=dict)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True, slots=True)
|
||||||
|
class TemplateRenderResult:
|
||||||
|
render_id: str
|
||||||
|
template_id: str
|
||||||
|
revision_id: str
|
||||||
|
revision: int
|
||||||
|
template_hash: str
|
||||||
|
input_hash: str
|
||||||
|
renderer_version: str
|
||||||
|
output_format: TemplateOutputFormat
|
||||||
|
content_type: str
|
||||||
|
filename: str
|
||||||
|
item_count: int
|
||||||
|
page_count: int
|
||||||
|
output_sha256: str
|
||||||
|
output_size_bytes: int
|
||||||
|
diagnostics: tuple[Mapping[str, object], ...] = ()
|
||||||
|
artifact: TemplateArtifactRef | None = None
|
||||||
|
generated_at: datetime | None = None
|
||||||
|
payload: bytes | None = None
|
||||||
|
|
||||||
|
|
||||||
|
@runtime_checkable
|
||||||
|
class TemplateCatalogProvider(Protocol):
|
||||||
|
def list_templates(
|
||||||
|
self,
|
||||||
|
session: object,
|
||||||
|
principal: object,
|
||||||
|
*,
|
||||||
|
query: str = "",
|
||||||
|
usage: str | None = None,
|
||||||
|
template_type: str | None = None,
|
||||||
|
locale: str | None = None,
|
||||||
|
limit: int = 100,
|
||||||
|
) -> Sequence[TemplateRef]: ...
|
||||||
|
|
||||||
|
def get_template(
|
||||||
|
self,
|
||||||
|
session: object,
|
||||||
|
principal: object,
|
||||||
|
*,
|
||||||
|
template_id: str,
|
||||||
|
revision: int | None = None,
|
||||||
|
) -> TemplateRef | None: ...
|
||||||
|
|
||||||
|
def check_compatibility(
|
||||||
|
self,
|
||||||
|
session: object,
|
||||||
|
principal: object,
|
||||||
|
*,
|
||||||
|
template_id: str,
|
||||||
|
revision: int | None = None,
|
||||||
|
usage: str | None = None,
|
||||||
|
output_format: str | None = None,
|
||||||
|
available_fields: Mapping[str, str] | Sequence[str] = (),
|
||||||
|
) -> TemplateCompatibility: ...
|
||||||
|
|
||||||
|
|
||||||
|
@runtime_checkable
|
||||||
|
class TemplateRendererProvider(Protocol):
|
||||||
|
def render(
|
||||||
|
self,
|
||||||
|
session: object,
|
||||||
|
principal: object,
|
||||||
|
*,
|
||||||
|
request: TemplateRenderRequest,
|
||||||
|
) -> TemplateRenderResult: ...
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"CAPABILITY_TEMPLATE_CATALOG",
|
||||||
|
"CAPABILITY_TEMPLATE_RENDERER",
|
||||||
|
"TemplateArtifactRef",
|
||||||
|
"TemplateCatalogProvider",
|
||||||
|
"TemplateCompatibility",
|
||||||
|
"TemplateCompatibilityError",
|
||||||
|
"TemplateContractError",
|
||||||
|
"TemplateFieldRequirement",
|
||||||
|
"TemplateNotFoundError",
|
||||||
|
"TemplateOutputFormat",
|
||||||
|
"TemplateOutputProfile",
|
||||||
|
"TemplateRef",
|
||||||
|
"TemplateRenderError",
|
||||||
|
"TemplateRenderMode",
|
||||||
|
"TemplateRenderRequest",
|
||||||
|
"TemplateRenderResult",
|
||||||
|
"TemplateRendererProvider",
|
||||||
|
"TemplateRevisionRef",
|
||||||
|
"TemplateType",
|
||||||
|
]
|
||||||
@@ -107,7 +107,7 @@ class Settings(BaseSettings):
|
|||||||
default=(
|
default=(
|
||||||
"tenancy,organizations,identity,idm,access,admin,dashboard,policy,"
|
"tenancy,organizations,identity,idm,access,admin,dashboard,policy,"
|
||||||
"audit,campaigns,files,mail,calendar,poll,scheduling,connectors,"
|
"audit,campaigns,files,mail,calendar,poll,scheduling,connectors,"
|
||||||
"datasources,dataflow,dist_lists,workflow_engine,workflow,views,search,risk_compliance,"
|
"datasources,dataflow,dist_lists,templates,workflow_engine,workflow,views,search,risk_compliance,"
|
||||||
"postbox,notifications,docs,ops"
|
"postbox,notifications,docs,ops"
|
||||||
),
|
),
|
||||||
alias="ENABLED_MODULES",
|
alias="ENABLED_MODULES",
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from govoplan_core.core.files import (
|
||||||
|
CAPABILITY_FILES_ARTIFACT_STORE,
|
||||||
|
ManagedArtifactRef,
|
||||||
|
ManagedArtifactStore,
|
||||||
|
ManagedArtifactWriteRequest,
|
||||||
|
)
|
||||||
|
from govoplan_core.core.templates import (
|
||||||
|
CAPABILITY_TEMPLATE_CATALOG,
|
||||||
|
CAPABILITY_TEMPLATE_RENDERER,
|
||||||
|
TemplateCatalogProvider,
|
||||||
|
TemplateRenderRequest,
|
||||||
|
TemplateRendererProvider,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class _Catalog:
|
||||||
|
def list_templates(self, session, principal, **kwargs):
|
||||||
|
del session, principal, kwargs
|
||||||
|
return ()
|
||||||
|
|
||||||
|
def get_template(self, session, principal, **kwargs):
|
||||||
|
del session, principal, kwargs
|
||||||
|
return None
|
||||||
|
|
||||||
|
def check_compatibility(self, session, principal, **kwargs):
|
||||||
|
del session, principal, kwargs
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class _Renderer:
|
||||||
|
def render(self, session, principal, *, request):
|
||||||
|
del session, principal, request
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class _Store:
|
||||||
|
def store_artifact(self, session, principal, *, request):
|
||||||
|
del session, principal
|
||||||
|
return ManagedArtifactRef(
|
||||||
|
file_asset_id="file-1",
|
||||||
|
file_version_id="version-1",
|
||||||
|
filename=request.filename,
|
||||||
|
display_path=request.filename,
|
||||||
|
content_type=request.content_type,
|
||||||
|
size_bytes=len(request.payload),
|
||||||
|
sha256="0" * 64,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TemplateContractTests(unittest.TestCase):
|
||||||
|
def test_capability_names_and_runtime_protocols_are_stable(self) -> None:
|
||||||
|
self.assertEqual("templates.catalog", CAPABILITY_TEMPLATE_CATALOG)
|
||||||
|
self.assertEqual("templates.renderer", CAPABILITY_TEMPLATE_RENDERER)
|
||||||
|
self.assertEqual("files.artifact_store", CAPABILITY_FILES_ARTIFACT_STORE)
|
||||||
|
self.assertIsInstance(_Catalog(), TemplateCatalogProvider)
|
||||||
|
self.assertIsInstance(_Renderer(), TemplateRendererProvider)
|
||||||
|
self.assertIsInstance(_Store(), ManagedArtifactStore)
|
||||||
|
|
||||||
|
def test_requests_do_not_expose_consumer_or_files_models(self) -> None:
|
||||||
|
render = TemplateRenderRequest(template_id="template-1")
|
||||||
|
artifact = ManagedArtifactWriteRequest(
|
||||||
|
filename="result.html",
|
||||||
|
payload=b"result",
|
||||||
|
content_type="text/html",
|
||||||
|
)
|
||||||
|
self.assertEqual((), render.items)
|
||||||
|
self.assertEqual("preview", render.mode)
|
||||||
|
self.assertEqual("Generated", artifact.folder)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
Generated
+22
@@ -38,6 +38,7 @@
|
|||||||
"@govoplan/risk-compliance-webui": "file:../../govoplan-risk-compliance/webui",
|
"@govoplan/risk-compliance-webui": "file:../../govoplan-risk-compliance/webui",
|
||||||
"@govoplan/scheduling-webui": "file:../../govoplan-scheduling/webui",
|
"@govoplan/scheduling-webui": "file:../../govoplan-scheduling/webui",
|
||||||
"@govoplan/search-webui": "file:../../govoplan-search/webui",
|
"@govoplan/search-webui": "file:../../govoplan-search/webui",
|
||||||
|
"@govoplan/templates-webui": "file:../../govoplan-templates/webui",
|
||||||
"@govoplan/tenancy-webui": "file:../../govoplan-tenancy/webui",
|
"@govoplan/tenancy-webui": "file:../../govoplan-tenancy/webui",
|
||||||
"@govoplan/views-webui": "file:../../govoplan-views/webui",
|
"@govoplan/views-webui": "file:../../govoplan-views/webui",
|
||||||
"@govoplan/voting-webui": "file:../../govoplan-voting/webui",
|
"@govoplan/voting-webui": "file:../../govoplan-voting/webui",
|
||||||
@@ -589,6 +590,23 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"../../govoplan-templates/webui": {
|
||||||
|
"name": "@govoplan/templates-webui",
|
||||||
|
"version": "0.1.14",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@govoplan/core-webui": "^0.1.14",
|
||||||
|
"lucide-react": "^1.23.0",
|
||||||
|
"react": ">=19.2.7 <20",
|
||||||
|
"react-dom": ">=19.2.7 <20",
|
||||||
|
"react-router": ">=8.3.0 <9",
|
||||||
|
"typescript": "^5.7.2"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@govoplan/core-webui": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"../../govoplan-tenancy/webui": {
|
"../../govoplan-tenancy/webui": {
|
||||||
"name": "@govoplan/tenancy-webui",
|
"name": "@govoplan/tenancy-webui",
|
||||||
"version": "0.1.8",
|
"version": "0.1.8",
|
||||||
@@ -1525,6 +1543,10 @@
|
|||||||
"resolved": "../../govoplan-search/webui",
|
"resolved": "../../govoplan-search/webui",
|
||||||
"link": true
|
"link": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@govoplan/templates-webui": {
|
||||||
|
"resolved": "../../govoplan-templates/webui",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
"node_modules/@govoplan/tenancy-webui": {
|
"node_modules/@govoplan/tenancy-webui": {
|
||||||
"resolved": "../../govoplan-tenancy/webui",
|
"resolved": "../../govoplan-tenancy/webui",
|
||||||
"link": true
|
"link": true
|
||||||
|
|||||||
@@ -79,6 +79,7 @@
|
|||||||
"@govoplan/scheduling-webui": "file:../../govoplan-scheduling/webui",
|
"@govoplan/scheduling-webui": "file:../../govoplan-scheduling/webui",
|
||||||
"@govoplan/search-webui": "file:../../govoplan-search/webui",
|
"@govoplan/search-webui": "file:../../govoplan-search/webui",
|
||||||
"@govoplan/tenancy-webui": "file:../../govoplan-tenancy/webui",
|
"@govoplan/tenancy-webui": "file:../../govoplan-tenancy/webui",
|
||||||
|
"@govoplan/templates-webui": "file:../../govoplan-templates/webui",
|
||||||
"@govoplan/views-webui": "file:../../govoplan-views/webui",
|
"@govoplan/views-webui": "file:../../govoplan-views/webui",
|
||||||
"@govoplan/voting-webui": "file:../../govoplan-voting/webui",
|
"@govoplan/voting-webui": "file:../../govoplan-voting/webui",
|
||||||
"@govoplan/workflow-webui": "file:../../govoplan-workflow/webui",
|
"@govoplan/workflow-webui": "file:../../govoplan-workflow/webui",
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ const packageByModule = {
|
|||||||
scheduling: "@govoplan/scheduling-webui",
|
scheduling: "@govoplan/scheduling-webui",
|
||||||
search: "@govoplan/search-webui",
|
search: "@govoplan/search-webui",
|
||||||
tenancy: "@govoplan/tenancy-webui",
|
tenancy: "@govoplan/tenancy-webui",
|
||||||
|
templates: "@govoplan/templates-webui",
|
||||||
views: "@govoplan/views-webui",
|
views: "@govoplan/views-webui",
|
||||||
voting: "@govoplan/voting-webui",
|
voting: "@govoplan/voting-webui",
|
||||||
workflow: "@govoplan/workflow-webui"
|
workflow: "@govoplan/workflow-webui"
|
||||||
@@ -53,6 +54,8 @@ const cases = [
|
|||||||
{ name: "dataflow-with-datasources", modules: ["datasources", "dataflow"] },
|
{ name: "dataflow-with-datasources", modules: ["datasources", "dataflow"] },
|
||||||
{ name: "distribution-lists-only", modules: ["dist_lists"] },
|
{ name: "distribution-lists-only", modules: ["dist_lists"] },
|
||||||
{ name: "distribution-lists-with-providers", modules: ["addresses", "policy", "organizations", "idm", "dataflow", "dist_lists"] },
|
{ name: "distribution-lists-with-providers", modules: ["addresses", "policy", "organizations", "idm", "dataflow", "dist_lists"] },
|
||||||
|
{ name: "templates-only", modules: ["templates"] },
|
||||||
|
{ name: "templates-with-files", modules: ["templates", "files"] },
|
||||||
{ name: "workflow-only", modules: ["workflow"] },
|
{ name: "workflow-only", modules: ["workflow"] },
|
||||||
{ name: "workflow-with-dataflow", modules: ["datasources", "dataflow", "workflow"] },
|
{ name: "workflow-with-dataflow", modules: ["datasources", "dataflow", "workflow"] },
|
||||||
{ name: "views-only", modules: ["views"] },
|
{ name: "views-only", modules: ["views"] },
|
||||||
@@ -82,7 +85,7 @@ const cases = [
|
|||||||
{ name: "docs-and-ops", modules: ["access", "docs", "ops"] },
|
{ name: "docs-and-ops", modules: ["access", "docs", "ops"] },
|
||||||
{ name: "approvals-only", modules: ["access", "approvals"] },
|
{ name: "approvals-only", modules: ["access", "approvals"] },
|
||||||
{ name: "voting-only", modules: ["access", "voting"] },
|
{ name: "voting-only", modules: ["access", "voting"] },
|
||||||
{ name: "full-product", modules: ["access", "tenancy", "admin", "addresses", "approvals", "policy", "audit", "dashboard", "datasources", "dataflow", "dist_lists", "workflow", "views", "organizations", "idm", "cases", "committee", "campaigns", "files", "forms", "forms_runtime", "mail", "notifications", "docs", "ops", "calendar", "scheduling", "portal", "postbox", "projects", "reporting", "risk_compliance", "search", "voting"] }
|
{ name: "full-product", modules: ["access", "tenancy", "admin", "addresses", "approvals", "policy", "audit", "dashboard", "datasources", "dataflow", "dist_lists", "templates", "workflow", "views", "organizations", "idm", "cases", "committee", "campaigns", "files", "forms", "forms_runtime", "mail", "notifications", "docs", "ops", "calendar", "scheduling", "portal", "postbox", "projects", "reporting", "risk_compliance", "search", "voting"] }
|
||||||
];
|
];
|
||||||
|
|
||||||
const npmExec = process.env.npm_execpath;
|
const npmExec = process.env.npm_execpath;
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ const defaultWebModulePackages = [
|
|||||||
"@govoplan/dataflow-webui",
|
"@govoplan/dataflow-webui",
|
||||||
"@govoplan/datasources-webui",
|
"@govoplan/datasources-webui",
|
||||||
"@govoplan/dashboard-webui",
|
"@govoplan/dashboard-webui",
|
||||||
|
"@govoplan/dist-lists-webui",
|
||||||
"@govoplan/docs-webui",
|
"@govoplan/docs-webui",
|
||||||
"@govoplan/files-webui",
|
"@govoplan/files-webui",
|
||||||
"@govoplan/forms-webui",
|
"@govoplan/forms-webui",
|
||||||
@@ -43,6 +44,7 @@ const defaultWebModulePackages = [
|
|||||||
"@govoplan/scheduling-webui",
|
"@govoplan/scheduling-webui",
|
||||||
"@govoplan/search-webui",
|
"@govoplan/search-webui",
|
||||||
"@govoplan/tenancy-webui",
|
"@govoplan/tenancy-webui",
|
||||||
|
"@govoplan/templates-webui",
|
||||||
"@govoplan/views-webui",
|
"@govoplan/views-webui",
|
||||||
"@govoplan/voting-webui",
|
"@govoplan/voting-webui",
|
||||||
"@govoplan/workflow-webui"
|
"@govoplan/workflow-webui"
|
||||||
@@ -235,6 +237,7 @@ export default defineConfig({
|
|||||||
fileURLToPath(new URL('../../govoplan-dataflow/webui', import.meta.url)),
|
fileURLToPath(new URL('../../govoplan-dataflow/webui', import.meta.url)),
|
||||||
fileURLToPath(new URL('../../govoplan-datasources/webui', import.meta.url)),
|
fileURLToPath(new URL('../../govoplan-datasources/webui', import.meta.url)),
|
||||||
fileURLToPath(new URL('../../govoplan-dashboard/webui', import.meta.url)),
|
fileURLToPath(new URL('../../govoplan-dashboard/webui', import.meta.url)),
|
||||||
|
fileURLToPath(new URL('../../govoplan-dist-lists/webui', import.meta.url)),
|
||||||
fileURLToPath(new URL('../../govoplan-docs/webui', import.meta.url)),
|
fileURLToPath(new URL('../../govoplan-docs/webui', import.meta.url)),
|
||||||
fileURLToPath(new URL('../../govoplan-files/webui', import.meta.url)),
|
fileURLToPath(new URL('../../govoplan-files/webui', import.meta.url)),
|
||||||
fileURLToPath(new URL('../../govoplan-forms/webui', import.meta.url)),
|
fileURLToPath(new URL('../../govoplan-forms/webui', import.meta.url)),
|
||||||
@@ -252,6 +255,7 @@ export default defineConfig({
|
|||||||
fileURLToPath(new URL('../../govoplan-scheduling/webui', import.meta.url)),
|
fileURLToPath(new URL('../../govoplan-scheduling/webui', import.meta.url)),
|
||||||
fileURLToPath(new URL('../../govoplan-search/webui', import.meta.url)),
|
fileURLToPath(new URL('../../govoplan-search/webui', import.meta.url)),
|
||||||
fileURLToPath(new URL('../../govoplan-tenancy/webui', import.meta.url)),
|
fileURLToPath(new URL('../../govoplan-tenancy/webui', import.meta.url)),
|
||||||
|
fileURLToPath(new URL('../../govoplan-templates/webui', import.meta.url)),
|
||||||
fileURLToPath(new URL('../../govoplan-views/webui', import.meta.url)),
|
fileURLToPath(new URL('../../govoplan-views/webui', import.meta.url)),
|
||||||
fileURLToPath(new URL('../../govoplan-voting/webui', import.meta.url)),
|
fileURLToPath(new URL('../../govoplan-voting/webui', import.meta.url)),
|
||||||
fileURLToPath(new URL('../../govoplan-workflow/webui', import.meta.url))
|
fileURLToPath(new URL('../../govoplan-workflow/webui', import.meta.url))
|
||||||
|
|||||||
Reference in New Issue
Block a user