feat: explain external work hand-offs

This commit is contained in:
2026-08-22 02:14:35 +02:00
parent d5214c641c
commit e4a4a42efa
4 changed files with 75 additions and 6 deletions
+3 -3
View File
@@ -4,15 +4,15 @@ build-backend = "setuptools.build_meta"
[project] [project]
name = "govoplan-workflow" name = "govoplan-workflow"
version = "0.1.19" version = "0.1.20"
description = "Optional visual authoring and inspection workspace for GovOPlaN Workflow Engine." description = "Optional visual authoring and inspection workspace for GovOPlaN Workflow Engine."
readme = "README.md" readme = "README.md"
requires-python = ">=3.12" requires-python = ">=3.12"
license = "AGPL-3.0-or-later" license = "AGPL-3.0-or-later"
authors = [{ name = "GovOPlaN" }] authors = [{ name = "GovOPlaN" }]
dependencies = [ dependencies = [
"govoplan-core>=0.1.18", "govoplan-core>=0.1.28",
"govoplan-workflow-engine>=0.1.18", "govoplan-workflow-engine>=0.1.19",
] ]
[tool.setuptools.packages.find] [tool.setuptools.packages.find]
+45 -1
View File
@@ -2,6 +2,7 @@ from __future__ import annotations
from govoplan_core.core.modules import ( from govoplan_core.core.modules import (
CapabilityDocumentation, CapabilityDocumentation,
DocumentationCondition,
DocumentationLink, DocumentationLink,
DocumentationTopic, DocumentationTopic,
FrontendModule, FrontendModule,
@@ -34,7 +35,7 @@ from govoplan_workflow_engine.backend.manifest import (
MODULE_ID = "workflow" MODULE_ID = "workflow"
MODULE_NAME = "Workflow" MODULE_NAME = "Workflow"
MODULE_VERSION = "0.1.19" MODULE_VERSION = "0.1.20"
SEMANTIC_SUBJECT_CAPABILITY = semantic_documentation_subject_capability(MODULE_ID) SEMANTIC_SUBJECT_CAPABILITY = semantic_documentation_subject_capability(MODULE_ID)
@@ -139,6 +140,49 @@ manifest = ModuleManifest(
), ),
), ),
documentation=( documentation=(
DocumentationTopic(
id="workflow.external-handoff-inspection",
title="Inspect and return to external work hand-offs",
summary=(
"Follow the exact linked module work while Workflow retains "
"its durable position and immutable reference."
),
body=(
"The runs dialog shows the current external hand-off state, exact "
"revision reference, safe linked-work action, timeout, and the "
"immutable Workflow evidence trail. Leaving the dialog or linked "
"Campaign page does not complete the step. Declared Campaign events "
"drive acceptance, reassignment, completion, rejection, and "
"cancellation without browser polling. A configured focused View "
"narrows the available surfaces while the step is active. If Views "
"is absent, the linked Campaign action remains available and the "
"dialog explains the reduced presentation. Missing optional Tasks or "
"Notifications is also shown without changing the hand-off outcome."
),
layer="available",
documentation_types=("admin", "user"),
audience=("operator", "workflow_designer", "campaign_manager"),
related_modules=(
"workflow_engine",
"campaigns",
"views",
"tasks",
"notifications",
),
conditions=(
DocumentationCondition(
any_scopes=(INSTANCE_READ_SCOPE, ADMIN_SCOPE),
),
),
metadata={
"kind": "workflow",
"help_contexts": [
"workflow.external-handoff",
"workflow.instances",
],
},
order=74,
),
DocumentationTopic( DocumentationTopic(
id="workflow.semantic-documentation", id="workflow.semantic-documentation",
title="Document configured workflow and step meaning", title="Document configured workflow and step meaning",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@govoplan/workflow-webui", "name": "@govoplan/workflow-webui",
"version": "0.1.19", "version": "0.1.20",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
@@ -285,6 +285,13 @@ export default function WorkflowRunsDialog({
const actionUrl = typeof currentStep?.handoff.action_url === "string" const actionUrl = typeof currentStep?.handoff.action_url === "string"
? currentStep.handoff.action_url ? currentStep.handoff.action_url
: ""; : "";
const unavailableOptionalCapabilities = Array.isArray(
currentStep?.handoff.unavailable_optional_capabilities
)
? currentStep.handoff.unavailable_optional_capabilities.filter(
(value): value is string => typeof value === "string" && Boolean(value)
)
: [];
const close = () => { const close = () => {
dispatchWorkflowViewChanged(null); dispatchWorkflowViewChanged(null);
onClose(); onClose();
@@ -390,6 +397,15 @@ export default function WorkflowRunsDialog({
{selected.error} {selected.error}
</DismissibleAlert> </DismissibleAlert>
) : null} ) : null}
{selected.view_context && !viewsRuntime ? (
<DismissibleAlert
tone="warning"
resetKey={`view-unavailable:${selected.id}:${selected.current_step_id ?? "none"}`}
>
The focused View is unavailable. Workflow position is preserved;
use the linked module action or ask an administrator to enable Views.
</DismissibleAlert>
) : null}
{currentStep ? ( {currentStep ? (
<section className="workflow-run-handoff"> <section className="workflow-run-handoff">
<div> <div>
@@ -417,9 +433,18 @@ export default function WorkflowRunsDialog({
&& currentStep.handoff.instructions ? ( && currentStep.handoff.instructions ? (
<p>{currentStep.handoff.instructions}</p> <p>{currentStep.handoff.instructions}</p>
) : null} ) : null}
{unavailableOptionalCapabilities.length ? (
<DismissibleAlert
tone="info"
resetKey={`optional:${currentStep.id}:${unavailableOptionalCapabilities.join(",")}`}
>
Optional integration unavailable: {unavailableOptionalCapabilities.join(", ")}.
The hand-off remains valid and resumable.
</DismissibleAlert>
) : null}
{actionUrl ? ( {actionUrl ? (
<a href={actionUrl}> <a href={actionUrl}>
Open linked Dataflow result <ExternalLink size={14} /> Open linked work <ExternalLink size={14} />
</a> </a>
) : null} ) : null}
{allowedActions.some((action) => action !== "cancel") ? ( {allowedActions.some((action) => action !== "cancel") ? (