Compare commits

..
4 Commits
Author SHA1 Message Date
zemion 982ef636b8 Release v0.1.15
Module Package Release / publish-packages (push) Successful in 13s
2026-08-04 15:22:52 +02:00
zemion 9aad49f16d Make package publication retries hash-safe 2026-08-04 14:19:04 +02:00
zemion 2b5c14385d Add Voting provider assurance contract 2026-08-04 14:01:05 +02:00
zemion bca3e46293 Publish npm artifacts from explicit local paths 2026-08-04 14:00:57 +02:00
9 changed files with 1956 additions and 566 deletions
+84 -6
View File
@@ -163,6 +163,78 @@ jobs:
with:
name: module-packages-${{ gitea.ref_name }}
path: dist/package-artifacts.json
- name: Check immutable registry state
shell: bash
env:
PACKAGE_TOKEN: ${{ secrets.GOVOPLAN_PACKAGE_TOKEN }}
run: |
set -euo pipefail
test -n "$PACKAGE_TOKEN"
python - <<'PY'
import hashlib
import json
import os
from pathlib import Path
import tomllib
from urllib.error import HTTPError
from urllib.parse import quote
from urllib.request import Request, urlopen
api_root = "https://git.add-ideas.de/api/v1/packages/GovOPlaN"
token = os.environ["PACKAGE_TOKEN"]
def should_publish(kind, name, version, path):
package_url = "/".join(
(api_root, kind, quote(name, safe=""), quote(version, safe=""), "files")
)
request = Request(
package_url,
headers={"Accept": "application/json", "Authorization": f"token {token}"},
)
try:
with urlopen(request, timeout=30) as response:
files = json.load(response)
except HTTPError as exc:
if exc.code == 404:
print(f"{kind} package {name}=={version} is not published yet")
return True
raise
if not isinstance(files, list) or len(files) != 1:
raise SystemExit(
f"immutable {kind} package {name}=={version} has an unexpected file set"
)
expected_sha256 = hashlib.sha256(path.read_bytes()).hexdigest()
if files[0].get("sha256") != expected_sha256:
raise SystemExit(
f"immutable {kind} package {name}=={version} already exists with a different SHA-256"
)
print(f"verified existing {kind} package {name}=={version} ({expected_sha256})")
return False
project = tomllib.loads(Path("pyproject.toml").read_text(encoding="utf-8"))["project"]
wheels = tuple(Path("dist").glob("*.whl"))
if len(wheels) != 1:
raise SystemExit("release build must contain exactly one wheel")
publish_pypi = should_publish(
"pypi", str(project["name"]), str(project["version"]), wheels[0]
)
tarballs = tuple(Path("dist").glob("*.tgz"))
if len(tarballs) > 1:
raise SystemExit("release build must contain at most one npm package")
publish_npm = False
if tarballs:
webui = json.loads(
Path(".package-webui/package.json").read_text(encoding="utf-8")
)
publish_npm = should_publish(
"npm", str(webui["name"]), str(webui["version"]), tarballs[0]
)
with Path(os.environ["GITEA_ENV"]).open("a", encoding="utf-8") as env_file:
env_file.write(f"PUBLISH_PYPI={int(publish_pypi)}\n")
env_file.write(f"PUBLISH_NPM={int(publish_npm)}\n")
PY
- name: Publish wheel and WebUI package
shell: bash
env:
@@ -172,13 +244,17 @@ jobs:
set -euo pipefail
test -n "$PACKAGE_USERNAME"
test -n "$PACKAGE_TOKEN"
TWINE_USERNAME="$PACKAGE_USERNAME" TWINE_PASSWORD="$PACKAGE_TOKEN" \
python -m twine upload --non-interactive \
--repository-url https://git.add-ideas.de/api/packages/GovOPlaN/pypi \
dist/*.whl
if [[ "$PUBLISH_PYPI" == 1 ]]; then
TWINE_USERNAME="$PACKAGE_USERNAME" TWINE_PASSWORD="$PACKAGE_TOKEN" \
python -m twine upload --non-interactive \
--repository-url https://git.add-ideas.de/api/packages/GovOPlaN/pypi \
dist/*.whl
else
echo "Exact wheel is already present; skipping immutable retry."
fi
shopt -s nullglob
webui_packages=(dist/*.tgz)
if (( ${#webui_packages[@]} )); then
if (( ${#webui_packages[@]} )) && [[ "$PUBLISH_NPM" == 1 ]]; then
npmrc="$(mktemp)"
trap 'rm -f "$npmrc"' EXIT
chmod 600 "$npmrc"
@@ -186,7 +262,9 @@ jobs:
'@govoplan:registry=https://git.add-ideas.de/api/packages/GovOPlaN/npm/' \
"//git.add-ideas.de/api/packages/GovOPlaN/npm/:_authToken=$PACKAGE_TOKEN" \
> "$npmrc"
NPM_CONFIG_USERCONFIG="$npmrc" npm publish "${webui_packages[0]}" \
NPM_CONFIG_USERCONFIG="$npmrc" npm publish "./${webui_packages[0]}" \
--ignore-scripts --access public \
--registry https://git.add-ideas.de/api/packages/GovOPlaN/npm/
elif (( ${#webui_packages[@]} )); then
echo "Exact WebUI package is already present; skipping immutable retry."
fi
+402
View File
@@ -663,6 +663,408 @@
"release": "0.1.14",
"squash_policy": "reviewed-manual",
"track": "release"
},
{
"heads": [
{
"owner": "govoplan-notifications",
"revision": "6e2f91ab4c70"
},
{
"owner": "govoplan-poll",
"revision": "6e7f8a9b0c1d"
},
{
"owner": "govoplan-dashboard",
"revision": "7b9d2f4a6c8e"
},
{
"owner": "govoplan-voting",
"revision": "8b9c0d1e2f3a"
},
{
"owner": "govoplan-mail",
"revision": "93b4c5d6e7f8"
},
{
"owner": "govoplan-forms-runtime",
"revision": "a3d5f7b9c1e2"
},
{
"owner": "govoplan-templates",
"revision": "a3f7c9d2e1b4"
},
{
"owner": "govoplan-organizations",
"revision": "a61e4d9c72b8"
},
{
"owner": "govoplan-mandates",
"revision": "a8b1c2d3e4f5"
},
{
"owner": "govoplan-audit",
"revision": "a8d1e4f7b2c5"
},
{
"owner": "govoplan-approvals",
"revision": "a91c4e72b5d8"
},
{
"owner": "govoplan-policy",
"revision": "a9c4e7b2d5f8"
},
{
"owner": "govoplan-idm",
"revision": "b1c2d3e4f5a6"
},
{
"owner": "govoplan-search",
"revision": "b2c3d4e5f607"
},
{
"owner": "govoplan-datasources",
"revision": "b8d2f5a0c3e7"
},
{
"owner": "govoplan-views",
"revision": "b8e4c1f7a2d9"
},
{
"owner": "govoplan-risk-compliance",
"revision": "b9c0d1e2f3a4"
},
{
"owner": "govoplan-services",
"revision": "b9c2d3e4f5a6"
},
{
"owner": "govoplan-parties",
"revision": "c0d3e4f5a6b7"
},
{
"owner": "govoplan-identity-trust",
"revision": "c3f5a7b9d1e2"
},
{
"owner": "govoplan-projects",
"revision": "c4a1e8f2d6b9"
},
{
"owner": "govoplan-addresses",
"revision": "c5d7e8f9a0b1"
},
{
"owner": "govoplan-access",
"revision": "c7e0a3d6f9b2"
},
{
"owner": "govoplan-reporting",
"revision": "c8d5e2f6a9b3"
},
{
"owner": "govoplan-scheduling",
"revision": "c9d4e7f1a2b3"
},
{
"owner": "govoplan-decisions",
"revision": "d1e4f5a6b7c8"
},
{
"owner": "govoplan-calendar",
"revision": "d24e5f607182"
},
{
"owner": "govoplan-committee",
"revision": "d8b9f0a1c2e3"
},
{
"owner": "govoplan-postbox",
"revision": "d8e3f6a9b2c5"
},
{
"owner": "govoplan-campaign",
"revision": "e3c8f4a5b6d7"
},
{
"owner": "govoplan-workflow-engine",
"revision": "e4a1f8c2d7b6"
},
{
"owner": "govoplan-encryption",
"revision": "e5b7c9d1f3a4"
},
{
"owner": "govoplan-dist-lists",
"revision": "e7c3a9d1b5f2"
},
{
"owner": "govoplan-files",
"revision": "f1a2b3c4d5e7"
},
{
"owner": "govoplan-core",
"revision": "f25c9d3e7a01"
},
{
"owner": "govoplan-dataflow",
"revision": "f6c2a9d4e7b1"
},
{
"owner": "govoplan-cases",
"revision": "f6d3a8b1c4e7"
},
{
"owner": "govoplan-connectors",
"revision": "f7c8d9e0a1b2"
}
],
"owner_heads": [
{
"owner": "govoplan-access",
"revisions": [
"c7e0a3d6f9b2"
]
},
{
"owner": "govoplan-addresses",
"revisions": [
"c5d7e8f9a0b1"
]
},
{
"owner": "govoplan-approvals",
"revisions": [
"a91c4e72b5d8"
]
},
{
"owner": "govoplan-audit",
"revisions": [
"a8d1e4f7b2c5"
]
},
{
"owner": "govoplan-calendar",
"revisions": [
"d24e5f607182"
]
},
{
"owner": "govoplan-campaign",
"revisions": [
"e3c8f4a5b6d7"
]
},
{
"owner": "govoplan-cases",
"revisions": [
"f6d3a8b1c4e7"
]
},
{
"owner": "govoplan-committee",
"revisions": [
"d8b9f0a1c2e3"
]
},
{
"owner": "govoplan-connectors",
"revisions": [
"f7c8d9e0a1b2"
]
},
{
"owner": "govoplan-core",
"revisions": [
"f25c9d3e7a01"
]
},
{
"owner": "govoplan-dashboard",
"revisions": [
"7b9d2f4a6c8e"
]
},
{
"owner": "govoplan-dataflow",
"revisions": [
"f6c2a9d4e7b1"
]
},
{
"owner": "govoplan-datasources",
"revisions": [
"b8d2f5a0c3e7"
]
},
{
"owner": "govoplan-decisions",
"revisions": [
"d1e4f5a6b7c8"
]
},
{
"owner": "govoplan-dist-lists",
"revisions": [
"e7c3a9d1b5f2"
]
},
{
"owner": "govoplan-encryption",
"revisions": [
"e5b7c9d1f3a4"
]
},
{
"owner": "govoplan-files",
"revisions": [
"f1a2b3c4d5e7"
]
},
{
"owner": "govoplan-forms",
"revisions": [
"e1f2a3b4c5d6"
]
},
{
"owner": "govoplan-forms-runtime",
"revisions": [
"a3d5f7b9c1e2"
]
},
{
"owner": "govoplan-identity",
"revisions": [
"5c6d7e8f9a10"
]
},
{
"owner": "govoplan-identity-trust",
"revisions": [
"c3f5a7b9d1e2"
]
},
{
"owner": "govoplan-idm",
"revisions": [
"b1c2d3e4f5a6"
]
},
{
"owner": "govoplan-mail",
"revisions": [
"93b4c5d6e7f8"
]
},
{
"owner": "govoplan-mandates",
"revisions": [
"a8b1c2d3e4f5"
]
},
{
"owner": "govoplan-notifications",
"revisions": [
"6e2f91ab4c70"
]
},
{
"owner": "govoplan-organizations",
"revisions": [
"a61e4d9c72b8"
]
},
{
"owner": "govoplan-parties",
"revisions": [
"c0d3e4f5a6b7"
]
},
{
"owner": "govoplan-policy",
"revisions": [
"a9c4e7b2d5f8"
]
},
{
"owner": "govoplan-poll",
"revisions": [
"6e7f8a9b0c1d"
]
},
{
"owner": "govoplan-postbox",
"revisions": [
"d8e3f6a9b2c5"
]
},
{
"owner": "govoplan-projects",
"revisions": [
"c4a1e8f2d6b9"
]
},
{
"owner": "govoplan-reporting",
"revisions": [
"c8d5e2f6a9b3"
]
},
{
"owner": "govoplan-risk-compliance",
"revisions": [
"b9c0d1e2f3a4"
]
},
{
"owner": "govoplan-scheduling",
"revisions": [
"c9d4e7f1a2b3"
]
},
{
"owner": "govoplan-search",
"revisions": [
"b2c3d4e5f607"
]
},
{
"owner": "govoplan-services",
"revisions": [
"b9c2d3e4f5a6"
]
},
{
"owner": "govoplan-templates",
"revisions": [
"a3f7c9d2e1b4"
]
},
{
"owner": "govoplan-views",
"revisions": [
"b8e4c1f7a2d9"
]
},
{
"owner": "govoplan-voting",
"revisions": [
"8b9c0d1e2f3a"
]
},
{
"owner": "govoplan-workflow-engine",
"revisions": [
"e4a1f8c2d7b6"
]
}
],
"recorded_at": "2026-08-04T13:09:52Z",
"release": "0.1.15",
"squash_policy": "reviewed-manual",
"track": "release"
}
],
"version": 1
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "govoplan-core"
version = "0.1.14"
version = "0.1.15"
description = "Reusable GovOPlaN platform core, access, tenancy, and RBAC components."
readme = "README.md"
requires-python = ">=3.12"
+196 -1
View File
@@ -2,7 +2,7 @@ from __future__ import annotations
from collections.abc import Mapping, Sequence
from dataclasses import dataclass, field
from datetime import datetime
from datetime import UTC, datetime
import json
from typing import Literal, Protocol, runtime_checkable
@@ -15,6 +15,20 @@ VOTING_ASSURANCE_CONFIDENTIAL = "confidential"
VOTING_ASSURANCE_SECRET = "secret"
VOTING_ASSURANCE_EXTERNAL_CERTIFIED = "external_certified"
VOTING_CERTIFICATION_NOT_CERTIFIED = "not_certified"
VOTING_CERTIFICATION_IN_EVALUATION = "in_evaluation"
VOTING_CERTIFICATION_CERTIFIED = "certified"
VOTING_CERTIFICATION_EXPIRED = "expired"
VOTING_CERTIFICATION_REVOKED = "revoked"
VotingProviderCertificationState = Literal[
"not_certified",
"in_evaluation",
"certified",
"expired",
"revoked",
]
class VotingCapabilityError(ValueError):
"""Stable error raised by Voting capability implementations."""
@@ -30,6 +44,119 @@ def voting_provider_capability(provider_id: str) -> str:
return f"{CAPABILITY_VOTING_PROVIDER_PREFIX}{normalized}"
@dataclass(frozen=True, slots=True)
class VotingProviderAssuranceDeclaration:
"""Pinned assurance and certification claim made by a Voting provider."""
provider_id: str
implementation_ref: str
supported_assurance_profiles: tuple[
Literal["confidential", "secret", "external_certified"], ...
]
certification_state: VotingProviderCertificationState
protocol_ref: str
protocol_version: str
certification_authority: str | None = None
certification_reference: str | None = None
certification_evidence_ref: str | None = None
certification_valid_from: datetime | None = None
certification_valid_until: datetime | None = None
notes: tuple[str, ...] = ()
def __post_init__(self) -> None:
normalized_id = str(self.provider_id or "").strip().lower()
voting_provider_capability(normalized_id)
if normalized_id != self.provider_id:
raise ValueError("Voting provider assurance id must be normalized.")
for field_name in ("implementation_ref", "protocol_ref", "protocol_version"):
if not str(getattr(self, field_name) or "").strip():
raise ValueError(
f"Voting provider assurance {field_name} is required."
)
profiles = tuple(self.supported_assurance_profiles)
allowed_profiles = {
VOTING_ASSURANCE_CONFIDENTIAL,
VOTING_ASSURANCE_SECRET,
VOTING_ASSURANCE_EXTERNAL_CERTIFIED,
}
if (
not profiles
or len(set(profiles)) != len(profiles)
or not set(profiles) <= allowed_profiles
):
raise ValueError(
"Voting provider assurance profiles must be unique supported external profiles."
)
if self.certification_state not in {
VOTING_CERTIFICATION_NOT_CERTIFIED,
VOTING_CERTIFICATION_IN_EVALUATION,
VOTING_CERTIFICATION_CERTIFIED,
VOTING_CERTIFICATION_EXPIRED,
VOTING_CERTIFICATION_REVOKED,
}:
raise ValueError("Voting provider certification state is invalid.")
valid_from = _aware_datetime(
self.certification_valid_from,
field_name="certification_valid_from",
)
valid_until = _aware_datetime(
self.certification_valid_until,
field_name="certification_valid_until",
)
if valid_from and valid_until and valid_until <= valid_from:
raise ValueError(
"Voting provider certification validity must end after it starts."
)
if self.certification_state == VOTING_CERTIFICATION_CERTIFIED:
required = (
self.certification_authority,
self.certification_reference,
self.certification_evidence_ref,
valid_from,
valid_until,
)
if any(value is None or value == "" for value in required):
raise ValueError(
"Certified Voting providers require authority, reference, evidence, and a validity window."
)
if len(self.notes) > 16 or any(not str(item or "").strip() for item in self.notes):
raise ValueError("Voting provider assurance notes must be bounded non-empty text.")
def is_currently_certified(self, *, at: datetime | None = None) -> bool:
if self.certification_state != VOTING_CERTIFICATION_CERTIFIED:
return False
moment = _aware_datetime(at or datetime.now(UTC), field_name="at")
valid_from = _aware_datetime(
self.certification_valid_from,
field_name="certification_valid_from",
)
valid_until = _aware_datetime(
self.certification_valid_until,
field_name="certification_valid_until",
)
return bool(valid_from and valid_until and valid_from <= moment < valid_until)
def to_dict(self) -> dict[str, object]:
return {
"provider_id": self.provider_id,
"implementation_ref": self.implementation_ref,
"supported_assurance_profiles": list(self.supported_assurance_profiles),
"certification_state": self.certification_state,
"protocol_ref": self.protocol_ref,
"protocol_version": self.protocol_version,
"certification_authority": self.certification_authority,
"certification_reference": self.certification_reference,
"certification_evidence_ref": self.certification_evidence_ref,
"certification_valid_from": _datetime_text(
self.certification_valid_from
),
"certification_valid_until": _datetime_text(
self.certification_valid_until
),
"notes": list(self.notes),
}
@dataclass(frozen=True, slots=True)
class VotingOption:
key: str
@@ -184,6 +311,8 @@ class ExternalVotingProvider(Protocol):
provider credentials must not cross this boundary.
"""
def assurance_declaration(self) -> VotingProviderAssuranceDeclaration: ...
def finalize_ballot(
self,
session: object,
@@ -283,6 +412,45 @@ class VotingBallotProvider(Protocol):
) -> VotingBallotRef: ...
def require_voting_provider_assurance(
provider: object,
*,
provider_id: str,
assurance_profile: str,
at: datetime | None = None,
) -> VotingProviderAssuranceDeclaration:
"""Validate and return the provider claim required for a frozen ballot."""
if not isinstance(provider, ExternalVotingProvider):
raise VotingCapabilityError("Voting provider does not implement the contract.")
try:
declaration = provider.assurance_declaration()
except (TypeError, ValueError) as exc:
raise VotingCapabilityError(
"Voting provider assurance declaration was rejected."
) from exc
if not isinstance(declaration, VotingProviderAssuranceDeclaration):
raise VotingCapabilityError(
"Voting provider returned an invalid assurance declaration."
)
normalized_provider_id = str(provider_id or "").strip().lower()
if declaration.provider_id != normalized_provider_id:
raise VotingCapabilityError(
"Voting provider assurance declaration does not match the selected provider."
)
if assurance_profile not in declaration.supported_assurance_profiles:
raise VotingCapabilityError(
"Voting provider does not support the selected assurance profile."
)
if (
assurance_profile == VOTING_ASSURANCE_EXTERNAL_CERTIFIED
and not declaration.is_currently_certified(at=at)
):
raise VotingCapabilityError(
"Externally certified Voting requires a currently valid provider certification."
)
return declaration
def _validate_provider_evidence(
evidence: Sequence[Mapping[str, object]],
) -> None:
@@ -330,6 +498,25 @@ def _reject_sensitive_evidence(value: object) -> None:
_reject_sensitive_evidence(nested)
def _aware_datetime(
value: datetime | None,
*,
field_name: str,
) -> datetime | None:
if value is None:
return None
if value.tzinfo is None or value.utcoffset() is None:
raise ValueError(
f"Voting provider assurance {field_name} must be timezone-aware."
)
return value.astimezone(UTC)
def _datetime_text(value: datetime | None) -> str | None:
aware = _aware_datetime(value, field_name="datetime")
return aware.isoformat() if aware is not None else None
__all__ = [
"CAPABILITY_VOTING_BALLOTS",
"CAPABILITY_VOTING_PROVIDER_PREFIX",
@@ -343,6 +530,11 @@ __all__ = [
"VOTING_ASSURANCE_EXTERNAL_CERTIFIED",
"VOTING_ASSURANCE_RECORDED",
"VOTING_ASSURANCE_SECRET",
"VOTING_CERTIFICATION_CERTIFIED",
"VOTING_CERTIFICATION_EXPIRED",
"VOTING_CERTIFICATION_IN_EVALUATION",
"VOTING_CERTIFICATION_NOT_CERTIFIED",
"VOTING_CERTIFICATION_REVOKED",
"VotingBallotCreateCommand",
"VotingBallotProvider",
"VotingBallotRef",
@@ -350,7 +542,10 @@ __all__ = [
"VotingCastCommand",
"VotingElector",
"VotingOption",
"VotingProviderAssuranceDeclaration",
"VotingProviderCertificationState",
"VotingReceipt",
"VotingResult",
"require_voting_provider_assurance",
"voting_provider_capability",
]
+66 -1
View File
@@ -1,8 +1,16 @@
from __future__ import annotations
from datetime import UTC, datetime, timedelta
import unittest
from govoplan_core.core.voting import VotingResult
from govoplan_core.core.voting import (
VOTING_CERTIFICATION_CERTIFIED,
VOTING_CERTIFICATION_IN_EVALUATION,
VotingCapabilityError,
VotingProviderAssuranceDeclaration,
VotingResult,
require_voting_provider_assurance,
)
def result_with_evidence(*evidence):
@@ -23,7 +31,64 @@ def result_with_evidence(*evidence):
)
class FakeProvider:
def __init__(self, declaration: VotingProviderAssuranceDeclaration) -> None:
self.declaration = declaration
def assurance_declaration(self) -> VotingProviderAssuranceDeclaration:
return self.declaration
def finalize_ballot(self, session, principal, *, request):
raise NotImplementedError
class VotingContractTests(unittest.TestCase):
def test_external_certification_requires_current_evidence_backed_claim(self) -> None:
now = datetime.now(UTC)
declaration = VotingProviderAssuranceDeclaration(
provider_id="certified_provider",
implementation_ref="certified-provider/adapter@1",
supported_assurance_profiles=("external_certified",),
certification_state=VOTING_CERTIFICATION_CERTIFIED,
protocol_ref="vendor:certified-ballot",
protocol_version="3.0",
certification_authority="Independent authority",
certification_reference="certificate-2026-1",
certification_evidence_ref="evidence://certificate-2026-1",
certification_valid_from=now - timedelta(days=1),
certification_valid_until=now + timedelta(days=1),
)
selected = require_voting_provider_assurance(
FakeProvider(declaration),
provider_id="certified_provider",
assurance_profile="external_certified",
at=now,
)
self.assertEqual("certificate-2026-1", selected.certification_reference)
self.assertEqual(
(now - timedelta(days=1)).isoformat(),
selected.to_dict()["certification_valid_from"],
)
def test_external_certification_rejects_evaluation_only_provider(self) -> None:
declaration = VotingProviderAssuranceDeclaration(
provider_id="candidate_provider",
implementation_ref="candidate-provider/adapter@1",
supported_assurance_profiles=("external_certified",),
certification_state=VOTING_CERTIFICATION_IN_EVALUATION,
protocol_ref="vendor:candidate-ballot",
protocol_version="1.0",
)
with self.assertRaisesRegex(VotingCapabilityError, "currently valid"):
require_voting_provider_assurance(
FakeProvider(declaration),
provider_id="candidate_provider",
assurance_profile="external_certified",
)
def test_accepts_sanitized_provider_evidence(self) -> None:
value = result_with_evidence(
{
+76 -76
View File
@@ -1,12 +1,12 @@
{
"name": "@govoplan/core-webui",
"version": "0.1.14",
"version": "0.1.15",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@govoplan/core-webui",
"version": "0.1.14",
"version": "0.1.15",
"dependencies": {
"@govoplan/access-webui": "file:../../govoplan-access/webui",
"@govoplan/addresses-webui": "file:../../govoplan-addresses/webui",
@@ -73,12 +73,12 @@
},
"../../govoplan-access/webui": {
"name": "@govoplan/access-webui",
"version": "0.1.11",
"version": "0.1.15",
"devDependencies": {
"typescript": "^5.7.2"
},
"peerDependencies": {
"@govoplan/core-webui": "^0.1.11",
"@govoplan/core-webui": "^0.1.15",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
"react-dom": ">=19.2.7 <20",
@@ -92,9 +92,9 @@
},
"../../govoplan-addresses/webui": {
"name": "@govoplan/addresses-webui",
"version": "0.1.9",
"version": "0.1.15",
"peerDependencies": {
"@govoplan/core-webui": "^0.1.11",
"@govoplan/core-webui": "^0.1.15",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
"react-dom": ">=19.2.7 <20",
@@ -108,12 +108,12 @@
},
"../../govoplan-admin/webui": {
"name": "@govoplan/admin-webui",
"version": "0.1.8",
"version": "0.1.15",
"devDependencies": {
"typescript": "^5.7.2"
},
"peerDependencies": {
"@govoplan/core-webui": "^0.1.9",
"@govoplan/core-webui": "^0.1.15",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
"react-dom": ">=19.2.7 <20",
@@ -127,9 +127,9 @@
},
"../../govoplan-approvals/webui": {
"name": "@govoplan/approvals-webui",
"version": "0.1.14",
"version": "0.1.15",
"peerDependencies": {
"@govoplan/core-webui": "^0.1.14",
"@govoplan/core-webui": "^0.1.15",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
"react-dom": ">=19.2.7 <20"
@@ -142,9 +142,9 @@
},
"../../govoplan-audit/webui": {
"name": "@govoplan/audit-webui",
"version": "0.1.8",
"version": "0.1.15",
"peerDependencies": {
"@govoplan/core-webui": "^0.1.9",
"@govoplan/core-webui": "^0.1.15",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
"react-dom": ">=19.2.7 <20",
@@ -158,9 +158,9 @@
},
"../../govoplan-calendar/webui": {
"name": "@govoplan/calendar-webui",
"version": "0.1.8",
"version": "0.1.15",
"peerDependencies": {
"@govoplan/core-webui": "^0.1.9",
"@govoplan/core-webui": "^0.1.15",
"@vitejs/plugin-react": "^5.2.0",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
@@ -177,7 +177,7 @@
},
"../../govoplan-campaign/webui": {
"name": "@govoplan/campaign-webui",
"version": "0.1.12",
"version": "0.1.15",
"dependencies": {
"read-excel-file": "9.2.0"
},
@@ -185,7 +185,7 @@
"typescript": "^5.7.2"
},
"peerDependencies": {
"@govoplan/core-webui": "^0.1.14",
"@govoplan/core-webui": "^0.1.15",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
"react-dom": ">=19.2.7 <20",
@@ -199,9 +199,9 @@
},
"../../govoplan-cases/webui": {
"name": "@govoplan/cases-webui",
"version": "0.1.8",
"version": "0.1.15",
"peerDependencies": {
"@govoplan/core-webui": "^0.1.14",
"@govoplan/core-webui": "^0.1.15",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
"react-dom": ">=19.2.7 <20",
@@ -215,9 +215,9 @@
},
"../../govoplan-committee/webui": {
"name": "@govoplan/committee-webui",
"version": "0.1.8",
"version": "0.1.15",
"peerDependencies": {
"@govoplan/core-webui": "^0.1.14",
"@govoplan/core-webui": "^0.1.15",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
"react-dom": ">=19.2.7 <20",
@@ -231,9 +231,9 @@
},
"../../govoplan-dashboard/webui": {
"name": "@govoplan/dashboard-webui",
"version": "0.1.8",
"version": "0.1.15",
"peerDependencies": {
"@govoplan/core-webui": "^0.1.8",
"@govoplan/core-webui": "^0.1.15",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
"react-dom": ">=19.2.7 <20",
@@ -247,9 +247,9 @@
},
"../../govoplan-dataflow/webui": {
"name": "@govoplan/dataflow-webui",
"version": "0.1.14",
"version": "0.1.15",
"peerDependencies": {
"@govoplan/core-webui": "^0.1.14",
"@govoplan/core-webui": "^0.1.15",
"@xyflow/react": "^12.11.2",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
@@ -265,9 +265,9 @@
},
"../../govoplan-datasources/webui": {
"name": "@govoplan/datasources-webui",
"version": "0.1.14",
"version": "0.1.15",
"peerDependencies": {
"@govoplan/core-webui": "^0.1.14",
"@govoplan/core-webui": "^0.1.15",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
"react-dom": ">=19.2.7 <20",
@@ -282,9 +282,9 @@
},
"../../govoplan-dist-lists/webui": {
"name": "@govoplan/dist-lists-webui",
"version": "0.1.14",
"version": "0.1.15",
"peerDependencies": {
"@govoplan/core-webui": "^0.1.14",
"@govoplan/core-webui": "^0.1.15",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
"react-dom": ">=19.2.7 <20",
@@ -299,9 +299,9 @@
},
"../../govoplan-docs/webui": {
"name": "@govoplan/docs-webui",
"version": "0.1.10",
"version": "0.1.15",
"peerDependencies": {
"@govoplan/core-webui": "^0.1.10",
"@govoplan/core-webui": "^0.1.15",
"@vitejs/plugin-react": "^5.2.0",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
@@ -318,9 +318,9 @@
},
"../../govoplan-encryption/webui": {
"name": "@govoplan/encryption-webui",
"version": "0.1.14",
"version": "0.1.15",
"peerDependencies": {
"@govoplan/core-webui": "^0.1.14",
"@govoplan/core-webui": "^0.1.15",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
"react-dom": ">=19.2.7 <20"
@@ -333,9 +333,9 @@
},
"../../govoplan-files/webui": {
"name": "@govoplan/files-webui",
"version": "0.1.9",
"version": "0.1.15",
"peerDependencies": {
"@govoplan/core-webui": "^0.1.9",
"@govoplan/core-webui": "^0.1.15",
"@vitejs/plugin-react": "^5.2.0",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
@@ -352,9 +352,9 @@
},
"../../govoplan-forms-runtime/webui": {
"name": "@govoplan/forms-runtime-webui",
"version": "0.1.14",
"version": "0.1.15",
"peerDependencies": {
"@govoplan/core-webui": "^0.1.14",
"@govoplan/core-webui": "^0.1.15",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
"react-dom": ">=19.2.7 <20",
@@ -368,9 +368,9 @@
},
"../../govoplan-forms/webui": {
"name": "@govoplan/forms-webui",
"version": "0.1.14",
"version": "0.1.15",
"peerDependencies": {
"@govoplan/core-webui": "^0.1.14",
"@govoplan/core-webui": "^0.1.15",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
"react-dom": ">=19.2.7 <20"
@@ -383,9 +383,9 @@
},
"../../govoplan-identity-trust/webui": {
"name": "@govoplan/identity-trust-webui",
"version": "0.1.14",
"version": "0.1.15",
"peerDependencies": {
"@govoplan/core-webui": "^0.1.14",
"@govoplan/core-webui": "^0.1.15",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
"react-dom": ">=19.2.7 <20"
@@ -398,9 +398,9 @@
},
"../../govoplan-idm/webui": {
"name": "@govoplan/idm-webui",
"version": "0.1.8",
"version": "0.1.15",
"peerDependencies": {
"@govoplan/core-webui": "^0.1.9",
"@govoplan/core-webui": "^0.1.15",
"@vitejs/plugin-react": "^5.2.0",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
@@ -417,12 +417,12 @@
},
"../../govoplan-mail/webui": {
"name": "@govoplan/mail-webui",
"version": "0.1.10",
"version": "0.1.15",
"devDependencies": {
"typescript": "^5.7.2"
},
"peerDependencies": {
"@govoplan/core-webui": "^0.1.10",
"@govoplan/core-webui": "^0.1.15",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
"react-dom": ">=19.2.7 <20",
@@ -436,9 +436,9 @@
},
"../../govoplan-notifications/webui": {
"name": "@govoplan/notifications-webui",
"version": "0.1.8",
"version": "0.1.15",
"peerDependencies": {
"@govoplan/core-webui": "^0.1.9",
"@govoplan/core-webui": "^0.1.15",
"@vitejs/plugin-react": "^5.2.0",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
@@ -455,9 +455,9 @@
},
"../../govoplan-ops/webui": {
"name": "@govoplan/ops-webui",
"version": "0.1.8",
"version": "0.1.15",
"peerDependencies": {
"@govoplan/core-webui": "^0.1.8",
"@govoplan/core-webui": "^0.1.15",
"@vitejs/plugin-react": "^5.2.0",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
@@ -474,9 +474,9 @@
},
"../../govoplan-organizations/webui": {
"name": "@govoplan/organizations-webui",
"version": "0.1.8",
"version": "0.1.15",
"peerDependencies": {
"@govoplan/core-webui": "^0.1.9",
"@govoplan/core-webui": "^0.1.15",
"@vitejs/plugin-react": "^5.2.0",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
@@ -493,9 +493,9 @@
},
"../../govoplan-policy/webui": {
"name": "@govoplan/policy-webui",
"version": "0.1.9",
"version": "0.1.15",
"peerDependencies": {
"@govoplan/core-webui": "^0.1.9",
"@govoplan/core-webui": "^0.1.15",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
"react-dom": ">=19.2.7 <20",
@@ -509,9 +509,9 @@
},
"../../govoplan-portal/webui": {
"name": "@govoplan/portal-webui",
"version": "0.1.8",
"version": "0.1.15",
"peerDependencies": {
"@govoplan/core-webui": "^0.1.14",
"@govoplan/core-webui": "^0.1.15",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
"react-dom": ">=19.2.7 <20",
@@ -525,9 +525,9 @@
},
"../../govoplan-postbox/webui": {
"name": "@govoplan/postbox-webui",
"version": "0.1.2",
"version": "0.1.15",
"peerDependencies": {
"@govoplan/core-webui": "^0.1.14",
"@govoplan/core-webui": "^0.1.15",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
"react-dom": ">=19.2.7 <20",
@@ -541,9 +541,9 @@
},
"../../govoplan-projects/webui": {
"name": "@govoplan/projects-webui",
"version": "0.1.14",
"version": "0.1.15",
"peerDependencies": {
"@govoplan/core-webui": "^0.1.14",
"@govoplan/core-webui": "^0.1.15",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
"react-dom": ">=19.2.7 <20",
@@ -557,9 +557,9 @@
},
"../../govoplan-reporting/webui": {
"name": "@govoplan/reporting-webui",
"version": "0.1.14",
"version": "0.1.15",
"peerDependencies": {
"@govoplan/core-webui": "^0.1.14",
"@govoplan/core-webui": "^0.1.15",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
"react-dom": ">=19.2.7 <20",
@@ -573,9 +573,9 @@
},
"../../govoplan-risk-compliance/webui": {
"name": "@govoplan/risk-compliance-webui",
"version": "0.1.8",
"version": "0.1.15",
"peerDependencies": {
"@govoplan/core-webui": "^0.1.14",
"@govoplan/core-webui": "^0.1.15",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
"react-dom": ">=19.2.7 <20",
@@ -589,9 +589,9 @@
},
"../../govoplan-scheduling/webui": {
"name": "@govoplan/scheduling-webui",
"version": "0.1.11",
"version": "0.1.15",
"peerDependencies": {
"@govoplan/core-webui": "^0.1.11",
"@govoplan/core-webui": "^0.1.15",
"@vitejs/plugin-react": "^5.2.0",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
@@ -608,9 +608,9 @@
},
"../../govoplan-search/webui": {
"name": "@govoplan/search-webui",
"version": "0.1.14",
"version": "0.1.15",
"peerDependencies": {
"@govoplan/core-webui": "^0.1.14",
"@govoplan/core-webui": "^0.1.15",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
"react-dom": ">=19.2.7 <20",
@@ -624,9 +624,9 @@
},
"../../govoplan-templates/webui": {
"name": "@govoplan/templates-webui",
"version": "0.1.14",
"version": "0.1.15",
"peerDependencies": {
"@govoplan/core-webui": "^0.1.14",
"@govoplan/core-webui": "^0.1.15",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
"react-dom": ">=19.2.7 <20",
@@ -641,9 +641,9 @@
},
"../../govoplan-tenancy/webui": {
"name": "@govoplan/tenancy-webui",
"version": "0.1.8",
"version": "0.1.15",
"peerDependencies": {
"@govoplan/core-webui": "^0.1.14",
"@govoplan/core-webui": "^0.1.15",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
"react-dom": ">=19.2.7 <20"
@@ -656,9 +656,9 @@
},
"../../govoplan-views/webui": {
"name": "@govoplan/views-webui",
"version": "0.1.0",
"version": "0.1.15",
"peerDependencies": {
"@govoplan/core-webui": "^0.1.14",
"@govoplan/core-webui": "^0.1.15",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
"react-dom": ">=19.2.7 <20",
@@ -672,9 +672,9 @@
},
"../../govoplan-voting/webui": {
"name": "@govoplan/voting-webui",
"version": "0.1.14",
"version": "0.1.15",
"peerDependencies": {
"@govoplan/core-webui": "^0.1.14",
"@govoplan/core-webui": "^0.1.15",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
"react-dom": ">=19.2.7 <20"
@@ -687,9 +687,9 @@
},
"../../govoplan-workflow/webui": {
"name": "@govoplan/workflow-webui",
"version": "0.1.14",
"version": "0.1.15",
"peerDependencies": {
"@govoplan/core-webui": "^0.1.14",
"@govoplan/core-webui": "^0.1.15",
"@xyflow/react": "^12.11.2",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@govoplan/core-webui",
"version": "0.1.14",
"version": "0.1.15",
"private": true,
"type": "module",
"main": "src/index.ts",
+14 -14
View File
@@ -1,6 +1,6 @@
{
"name": "@govoplan/core-webui",
"version": "0.1.14",
"version": "0.1.15",
"private": true,
"type": "module",
"main": "src/index.ts",
@@ -26,19 +26,19 @@
"preview": "vite preview --host 127.0.0.1 --port 4173"
},
"dependencies": {
"@govoplan/access-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-access.git#v0.1.8",
"@govoplan/admin-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-admin.git#v0.1.8",
"@govoplan/audit-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-audit.git#v0.1.8",
"@govoplan/calendar-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-calendar.git#v0.1.8",
"@govoplan/dashboard-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-dashboard.git#v0.1.8",
"@govoplan/docs-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-docs.git#v0.1.8",
"@govoplan/files-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-files.git#v0.1.8",
"@govoplan/idm-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-idm.git#v0.1.8",
"@govoplan/mail-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-mail.git#v0.1.10",
"@govoplan/campaign-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-campaign.git#v0.1.11",
"@govoplan/organizations-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-organizations.git#v0.1.8",
"@govoplan/ops-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-ops.git#v0.1.8",
"@govoplan/policy-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-policy.git#v0.1.8",
"@govoplan/access-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-access.git#v0.1.15",
"@govoplan/admin-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-admin.git#v0.1.15",
"@govoplan/audit-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-audit.git#v0.1.15",
"@govoplan/calendar-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-calendar.git#v0.1.15",
"@govoplan/dashboard-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-dashboard.git#v0.1.15",
"@govoplan/docs-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-docs.git#v0.1.15",
"@govoplan/files-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-files.git#v0.1.15",
"@govoplan/idm-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-idm.git#v0.1.15",
"@govoplan/mail-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-mail.git#v0.1.15",
"@govoplan/campaign-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-campaign.git#v0.1.15",
"@govoplan/organizations-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-organizations.git#v0.1.15",
"@govoplan/ops-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-ops.git#v0.1.15",
"@govoplan/policy-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-policy.git#v0.1.15",
"@tiptap/core": "^3.29.2",
"@tiptap/extension-image": "^3.29.2",
"@tiptap/pm": "^3.29.2",