diff --git a/AGENTS.md b/AGENTS.md index ed68906..ab10b79 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -26,8 +26,8 @@ PATH=/mnt/DATA/git/govoplan-core/webui/node_modules/.bin:/home/zemion/.nvm/versi For combined checks, run: ```bash -cd /mnt/DATA/git/govoplan-core -./scripts/check-focused.sh +cd /mnt/DATA/git/govoplan +tools/checks/check-focused.sh ``` ## Working Rules diff --git a/README.md b/README.md index 9108a46..9e5bc5e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ # govoplan-campaign + +**Repository type:** module (domain). + + GovOPlaN Campaign is the campaign authoring, validation, review, sending-control, and reporting module. It bundles backend campaign APIs with the campaign WebUI package. ## Ownership diff --git a/package.json b/package.json index ff9d016..a3036dd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@govoplan/campaign-webui", - "version": "0.1.7", + "version": "0.1.8", "private": true, "type": "module", "main": "webui/src/index.ts", @@ -22,7 +22,7 @@ "read-excel-file": "9.2.0" }, "peerDependencies": { - "@govoplan/core-webui": "^0.1.7", + "@govoplan/core-webui": "^0.1.8", "lucide-react": "^1.23.0", "react": "^19.0.0", "react-dom": "^19.0.0", diff --git a/pyproject.toml b/pyproject.toml index add0e1a..6daee6d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,14 +4,14 @@ build-backend = "setuptools.build_meta" [project] name = "govoplan-campaign" -version = "0.1.7" +version = "0.1.8" description = "GovOPlaN campaigns module with backend and WebUI integration." readme = "README.md" requires-python = ">=3.12" license = { file = "LICENSE" } authors = [{ name = "GovOPlaN" }] dependencies = [ - "govoplan-core>=0.1.7", + "govoplan-core>=0.1.8", "jsonschema>=4,<5", "pydantic>=2,<3", "SQLAlchemy>=2,<3", diff --git a/src/govoplan_campaign/backend/manifest.py b/src/govoplan_campaign/backend/manifest.py index f908822..46ecf21 100644 --- a/src/govoplan_campaign/backend/manifest.py +++ b/src/govoplan_campaign/backend/manifest.py @@ -142,7 +142,7 @@ def _campaigns_router(context: ModuleContext): manifest = ModuleManifest( id="campaigns", name="Campaigns", - version="0.1.7", + version="0.1.8", required_capabilities=(CAPABILITY_AUTH_PRINCIPAL_RESOLVER, CAPABILITY_AUTH_PERMISSION_EVALUATOR), optional_dependencies=("files", "mail"), provides_interfaces=( diff --git a/src/govoplan_campaign/backend/migrations/versions/2c3d4e5f7081_recipient_import_mapping_profiles.py b/src/govoplan_campaign/backend/migrations/dev_versions/2c3d4e5f7081_recipient_import_mapping_profiles.py similarity index 100% rename from src/govoplan_campaign/backend/migrations/versions/2c3d4e5f7081_recipient_import_mapping_profiles.py rename to src/govoplan_campaign/backend/migrations/dev_versions/2c3d4e5f7081_recipient_import_mapping_profiles.py diff --git a/src/govoplan_campaign/backend/migrations/dev_versions/__init__.py b/src/govoplan_campaign/backend/migrations/dev_versions/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/govoplan_campaign/backend/migrations/versions/2c3d4e5f7081_v017_campaign_baseline.py b/src/govoplan_campaign/backend/migrations/versions/2c3d4e5f7081_v017_campaign_baseline.py new file mode 100644 index 0000000..011d9c2 --- /dev/null +++ b/src/govoplan_campaign/backend/migrations/versions/2c3d4e5f7081_v017_campaign_baseline.py @@ -0,0 +1,51 @@ +"""v0.1.7 campaign baseline + +Revision ID: 2c3d4e5f7081 +Revises: None +Create Date: 2026-07-11 00:00:00.000000 +""" +from __future__ import annotations + +from alembic import op +import sqlalchemy as sa + + +revision = '2c3d4e5f7081' +down_revision = None +branch_labels = None +depends_on = '4f2a9c8e7b6d' + + +def upgrade() -> None: + op.create_table('campaign_recipient_import_mapping_profiles', + sa.Column('id', sa.String(length=36), nullable=False), + sa.Column('tenant_id', sa.String(length=36), nullable=False), + sa.Column('owner_user_id', sa.String(length=36), nullable=False), + sa.Column('name', sa.String(length=255), nullable=False), + sa.Column('column_count', sa.Integer(), nullable=False), + sa.Column('headers', sa.JSON(), nullable=False), + sa.Column('normalized_headers', sa.JSON(), nullable=False), + sa.Column('ordered_header_fingerprint', sa.String(length=64), nullable=False), + sa.Column('unordered_header_fingerprint', sa.String(length=64), nullable=False), + sa.Column('delimiter', sa.String(length=8), nullable=False), + sa.Column('header_rows', sa.Integer(), nullable=False), + sa.Column('quoted', sa.Boolean(), nullable=False), + sa.Column('value_separators', sa.String(length=50), nullable=False), + sa.Column('mappings', sa.JSON(), nullable=False), + sa.Column('created_at', sa.DateTime(timezone=True), nullable=False), + sa.Column('updated_at', sa.DateTime(timezone=True), nullable=False), + sa.ForeignKeyConstraint(['owner_user_id'], ['access_users.id'], name=op.f('fk_campaign_recipient_import_mapping_profiles_owner_user_id_access_users'), ondelete='CASCADE'), + sa.ForeignKeyConstraint(['tenant_id'], ['core_scopes.id'], name=op.f('fk_campaign_recipient_import_mapping_profiles_tenant_id_scopes'), ondelete='CASCADE'), + sa.PrimaryKeyConstraint('id', name=op.f('pk_campaign_recipient_import_mapping_profiles')) + ) + op.create_index(op.f('ix_campaign_recipient_import_mapping_profiles_ordered_header_fingerprint'), 'campaign_recipient_import_mapping_profiles', ['ordered_header_fingerprint'], unique=False) + op.create_index(op.f('ix_campaign_recipient_import_mapping_profiles_owner_user_id'), 'campaign_recipient_import_mapping_profiles', ['owner_user_id'], unique=False) + op.create_index(op.f('ix_campaign_recipient_import_mapping_profiles_tenant_id'), 'campaign_recipient_import_mapping_profiles', ['tenant_id'], unique=False) + op.create_index(op.f('ix_campaign_recipient_import_mapping_profiles_unordered_header_fingerprint'), 'campaign_recipient_import_mapping_profiles', ['unordered_header_fingerprint'], unique=False) + op.create_index('ix_recipient_import_profiles_ordered_fp', 'campaign_recipient_import_mapping_profiles', ['tenant_id', 'owner_user_id', 'ordered_header_fingerprint'], unique=False) + op.create_index('ix_recipient_import_profiles_owner', 'campaign_recipient_import_mapping_profiles', ['tenant_id', 'owner_user_id'], unique=False) + op.create_index('ix_recipient_import_profiles_unordered_fp', 'campaign_recipient_import_mapping_profiles', ['tenant_id', 'owner_user_id', 'unordered_header_fingerprint'], unique=False) + + +def downgrade() -> None: + op.drop_table('campaign_recipient_import_mapping_profiles') diff --git a/webui/package.json b/webui/package.json index 8381507..fec0a74 100644 --- a/webui/package.json +++ b/webui/package.json @@ -1,6 +1,6 @@ { "name": "@govoplan/campaign-webui", - "version": "0.1.7", + "version": "0.1.8", "private": true, "type": "module", "main": "src/index.ts", @@ -17,7 +17,7 @@ "read-excel-file": "9.2.0" }, "peerDependencies": { - "@govoplan/core-webui": "^0.1.7", + "@govoplan/core-webui": "^0.1.8", "lucide-react": "^1.23.0", "react": "^19.0.0", "react-dom": "^19.0.0", diff --git a/webui/src/module.ts b/webui/src/module.ts index cdfa252..10158ef 100644 --- a/webui/src/module.ts +++ b/webui/src/module.ts @@ -30,13 +30,13 @@ export const campaignModule: PlatformWebModule = { { to: "/operator", label: "i18n:govoplan-campaign.operator_queue.ddf23260", - iconName: "activity", + iconName: "radio-tower", anyOf: operatorScopes, order: 30 }, - { to: "/reports", label: "i18n:govoplan-campaign.reports.88bc3fe3", iconName: "reports", anyOf: ["campaigns:report:read"], order: 70 }, + { to: "/reports", label: "i18n:govoplan-campaign.reports.88bc3fe3", iconName: "clipboard-pen-line", anyOf: ["campaigns:report:read"], order: 70 }, { to: "/address-book", label: "i18n:govoplan-campaign.address_book.f6327f59", iconName: "users", order: 80 }, - { to: "/templates", label: "i18n:govoplan-campaign.templates.f25b700e", iconName: "form", order: 90 }], + { to: "/templates", label: "i18n:govoplan-campaign.templates.f25b700e", iconName: "layout-template", order: 90 }], routes: [ { path: "/campaigns", anyOf: campaignRead, order: 20, render: ({ settings }) => createElement(CampaignListPage, { settings }) },