fix: merge main branch and renumber migration 027→037
Resolve 3 merge conflicts and renumber the automation_hooks migration to follow main's migration chain (036_add_document_translation_fields). Conflicts resolved: - app/api/__init__.py: add automation_router alongside main's new routers - app/utils/settings_service.py: add automation_hooks_enabled alongside compliance_enabled - tests/conftest.py: add AutomationHook alongside AuditLog/ComplianceTemplate imports Migration renumbered: - 027_add_automation_hooks → 037_add_automation_hooks - down_revision: 026_add_scheduled_jobs → 036_add_document_translation_fields Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Processing Pipelines – DocuElevate{% endblock %}
|
||||
{% block title %}{{ _("pipelines.title") }} – DocuElevate{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container mx-auto px-4 py-8" x-data="pipelinesApp()" x-init="init()">
|
||||
@@ -9,13 +9,13 @@
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold text-gray-900 dark:text-white flex items-center gap-2">
|
||||
<i class="fas fa-project-diagram text-blue-500" aria-hidden="true"></i>
|
||||
Processing Pipelines
|
||||
{{ _("pipelines.page_title") }}
|
||||
</h1>
|
||||
<p class="text-gray-500 dark:text-gray-400 text-sm mt-1">
|
||||
Define and manage custom document processing workflows.
|
||||
System pipelines (created by admins) are shown with a
|
||||
<span class="text-xs font-semibold text-purple-700 bg-purple-50 border border-purple-200 rounded px-1">System</span>
|
||||
badge and are visible to all users.
|
||||
{{ _("pipelines.subtitle_intro") }}
|
||||
{{ _("pipelines.subtitle_system_pre") }}
|
||||
<span class="text-xs font-semibold text-purple-700 bg-purple-50 border border-purple-200 rounded px-1">{{ _("pipelines.system_label") }}</span>
|
||||
{{ _("pipelines.subtitle_system_post") }}
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
@@ -24,7 +24,7 @@
|
||||
class="inline-flex items-center px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
||||
style="min-height:44px;"
|
||||
>
|
||||
<i class="fas fa-plus mr-2" aria-hidden="true"></i> New Pipeline
|
||||
<i class="fas fa-plus mr-2" aria-hidden="true"></i> {{ _("pipelines.new_pipeline_btn") }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
<template x-if="loading">
|
||||
<div class="text-center py-12 text-gray-400">
|
||||
<i class="fas fa-spinner fa-spin text-3xl mb-3" aria-hidden="true"></i>
|
||||
<p>Loading pipelines…</p>
|
||||
<p>{{ _("pipelines.loading") }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -59,15 +59,15 @@
|
||||
<template x-if="!loading && pipelines.length === 0">
|
||||
<div class="text-center py-16 bg-white dark:bg-gray-800 rounded-lg shadow">
|
||||
<i class="fas fa-project-diagram text-5xl text-gray-300 mb-4" aria-hidden="true"></i>
|
||||
<h2 class="text-xl font-semibold text-gray-700 dark:text-gray-300 mb-2">No pipelines yet</h2>
|
||||
<p class="text-gray-500 dark:text-gray-400 mb-6">Create your first pipeline to define custom document processing workflows.</p>
|
||||
<h2 class="text-xl font-semibold text-gray-700 dark:text-gray-300 mb-2">{{ _("pipelines.empty_state") }}</h2>
|
||||
<p class="text-gray-500 dark:text-gray-400 mb-6">{{ _("pipelines.empty_state_hint") }}</p>
|
||||
<button
|
||||
type="button"
|
||||
@click="openCreatePipelineModal()"
|
||||
class="inline-flex items-center px-5 py-2.5 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium rounded-md"
|
||||
style="min-height:44px;"
|
||||
>
|
||||
<i class="fas fa-plus mr-2" aria-hidden="true"></i> Create Pipeline
|
||||
<i class="fas fa-plus mr-2" aria-hidden="true"></i> {{ _("pipelines.create") }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
@@ -84,13 +84,13 @@
|
||||
<h2 class="text-lg font-semibold text-gray-900 dark:text-white" x-text="pipeline.name"></h2>
|
||||
<!-- Badges -->
|
||||
<template x-if="pipeline.owner_id === null">
|
||||
<span class="text-xs font-semibold text-purple-700 bg-purple-50 border border-purple-200 rounded px-1.5 py-0.5">System</span>
|
||||
<span class="text-xs font-semibold text-purple-700 bg-purple-50 border border-purple-200 rounded px-1.5 py-0.5">{{ _("pipelines.system_label") }}</span>
|
||||
</template>
|
||||
<template x-if="pipeline.is_default">
|
||||
<span class="text-xs font-semibold text-green-700 bg-green-50 border border-green-200 rounded px-1.5 py-0.5">Default</span>
|
||||
<span class="text-xs font-semibold text-green-700 bg-green-50 border border-green-200 rounded px-1.5 py-0.5">{{ _("pipelines.default_label") }}</span>
|
||||
</template>
|
||||
<template x-if="!pipeline.is_active">
|
||||
<span class="text-xs font-semibold text-gray-500 bg-gray-100 border border-gray-200 rounded px-1.5 py-0.5">Inactive</span>
|
||||
<span class="text-xs font-semibold text-gray-500 bg-gray-100 border border-gray-200 rounded px-1.5 py-0.5">{{ _("pipelines.inactive_label") }}</span>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
@@ -115,7 +115,7 @@
|
||||
style="min-height:36px;"
|
||||
:aria-label="`Edit pipeline ${pipeline.name}`"
|
||||
>
|
||||
<i class="fas fa-pencil-alt mr-1" aria-hidden="true"></i> Edit
|
||||
<i class="fas fa-pencil-alt mr-1" aria-hidden="true"></i> {{ _("common.edit") }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@@ -124,7 +124,7 @@
|
||||
style="min-height:36px;"
|
||||
:aria-label="`Delete pipeline ${pipeline.name}`"
|
||||
>
|
||||
<i class="fas fa-trash mr-1" aria-hidden="true"></i> Delete
|
||||
<i class="fas fa-trash mr-1" aria-hidden="true"></i> {{ _("common.delete") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -139,7 +139,7 @@
|
||||
|
||||
<!-- Step list -->
|
||||
<template x-if="(pipeline.steps || []).length === 0">
|
||||
<p class="text-sm text-gray-400 italic mb-3">No steps defined. Add a step to start building your pipeline.</p>
|
||||
<p class="text-sm text-gray-400 italic mb-3">{{ _("pipelines.no_steps") }}</p>
|
||||
</template>
|
||||
|
||||
<template x-if="(pipeline.steps || []).length > 0">
|
||||
@@ -153,7 +153,7 @@
|
||||
<p class="text-xs text-gray-400 truncate" x-text="step.step_type"></p>
|
||||
</div>
|
||||
<template x-if="!step.enabled">
|
||||
<span class="text-xs text-gray-400 bg-gray-200 rounded px-1.5 py-0.5 flex-shrink-0">Disabled</span>
|
||||
<span class="text-xs text-gray-400 bg-gray-200 rounded px-1.5 py-0.5 flex-shrink-0">{{ _("pipelines.disabled_label") }}</span>
|
||||
</template>
|
||||
</div>
|
||||
<div class="flex items-center gap-1.5 flex-shrink-0">
|
||||
@@ -201,7 +201,7 @@
|
||||
style="min-height:36px;"
|
||||
:aria-label="`Add step to ${pipeline.name}`"
|
||||
>
|
||||
<i class="fas fa-plus mr-1" aria-hidden="true"></i> Add Step
|
||||
<i class="fas fa-plus mr-1" aria-hidden="true"></i> {{ _("pipelines.add_step_btn") }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -241,7 +241,7 @@
|
||||
<!-- Name -->
|
||||
<div>
|
||||
<label for="pipelineName" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
||||
Name <span aria-hidden="true" class="text-red-500">*</span>
|
||||
{{ _("common.name") }} <span aria-hidden="true" class="text-red-500">*</span>
|
||||
</label>
|
||||
<input
|
||||
id="pipelineName"
|
||||
@@ -250,21 +250,21 @@
|
||||
maxlength="255"
|
||||
required
|
||||
class="w-full border border-gray-300 dark:border-gray-600 rounded-md px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 dark:bg-gray-700 dark:text-white"
|
||||
placeholder="My pipeline"
|
||||
placeholder="{{ _('pipelines.name_placeholder') }}"
|
||||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Description -->
|
||||
<div>
|
||||
<label for="pipelineDesc" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Description</label>
|
||||
<label for="pipelineDesc" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">{{ _("common.description") }}</label>
|
||||
<textarea
|
||||
id="pipelineDesc"
|
||||
x-model="pipelineModal.form.description"
|
||||
rows="2"
|
||||
maxlength="4096"
|
||||
class="w-full border border-gray-300 dark:border-gray-600 rounded-md px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 dark:bg-gray-700 dark:text-white resize-none"
|
||||
placeholder="Optional description"
|
||||
placeholder="{{ _('pipelines.description_placeholder') }}"
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
@@ -276,7 +276,7 @@
|
||||
x-model="pipelineModal.form.is_default"
|
||||
class="rounded border-gray-300 text-blue-600 focus:ring-blue-400"
|
||||
/>
|
||||
<span class="text-sm text-gray-700 dark:text-gray-300">Set as my default pipeline</span>
|
||||
<span class="text-sm text-gray-700 dark:text-gray-300">{{ _("pipelines.set_default") }}</span>
|
||||
</label>
|
||||
<label class="inline-flex items-center gap-2 cursor-pointer">
|
||||
<input
|
||||
@@ -284,7 +284,7 @@
|
||||
x-model="pipelineModal.form.is_active"
|
||||
class="rounded border-gray-300 text-blue-600 focus:ring-blue-400"
|
||||
/>
|
||||
<span class="text-sm text-gray-700 dark:text-gray-300">Active</span>
|
||||
<span class="text-sm text-gray-700 dark:text-gray-300">{{ _("pipelines.active_label") }}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@@ -296,7 +296,7 @@
|
||||
x-model="pipelineModal.form.system"
|
||||
class="rounded border-gray-300 text-purple-600 focus:ring-purple-400"
|
||||
/>
|
||||
<span class="text-sm text-gray-700 dark:text-gray-300">System pipeline (visible to all users)</span>
|
||||
<span class="text-sm text-gray-700 dark:text-gray-300">{{ _("pipelines.system_pipeline_label") }}</span>
|
||||
</label>
|
||||
</template>
|
||||
|
||||
@@ -310,16 +310,16 @@
|
||||
@click="closePipelineModal()"
|
||||
class="px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded-md hover:bg-gray-50"
|
||||
style="min-height:44px;"
|
||||
>Cancel</button>
|
||||
>{{ _("common.cancel") }}</button>
|
||||
<button
|
||||
type="submit"
|
||||
:disabled="pipelineModal.saving"
|
||||
class="px-4 py-2 text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 disabled:opacity-60 rounded-md"
|
||||
style="min-height:44px;"
|
||||
>
|
||||
<template x-if="pipelineModal.saving">
|
||||
<i class="fas fa-spinner fa-spin mr-1" aria-hidden="true"></i>
|
||||
</template>
|
||||
<template x-if="pipelineModal.saving">
|
||||
<i class="fas fa-spinner fa-spin mr-1" aria-hidden="true"></i>
|
||||
</template>
|
||||
<span x-text="pipelineModal.editMode ? 'Save Changes' : 'Create'"></span>
|
||||
</button>
|
||||
</div>
|
||||
@@ -358,7 +358,7 @@
|
||||
<!-- Step type -->
|
||||
<div>
|
||||
<label for="stepType" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
||||
Step Type <span aria-hidden="true" class="text-red-500">*</span>
|
||||
{{ _("pipelines.step_type_label") }} <span aria-hidden="true" class="text-red-500">*</span>
|
||||
</label>
|
||||
<select
|
||||
id="stepType"
|
||||
@@ -366,7 +366,7 @@
|
||||
:disabled="stepModal.editMode"
|
||||
class="w-full border border-gray-300 dark:border-gray-600 rounded-md px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 dark:bg-gray-700 dark:text-white"
|
||||
>
|
||||
<option value="">— select —</option>
|
||||
<option value="">{{ _("common.select_placeholder") }}</option>
|
||||
<template x-for="[key, meta] in Object.entries(stepTypes)" :key="key">
|
||||
<option :value="key" x-text="meta.label"></option>
|
||||
</template>
|
||||
@@ -379,7 +379,7 @@
|
||||
<!-- Custom label -->
|
||||
<div>
|
||||
<label for="stepLabel" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
||||
Custom Label <span class="text-gray-400 font-normal">(optional)</span>
|
||||
{{ _("pipelines.custom_label_label") }} <span class="text-gray-400 font-normal">{{ _("pipelines.optional_suffix") }}</span>
|
||||
</label>
|
||||
<input
|
||||
id="stepLabel"
|
||||
@@ -387,7 +387,7 @@
|
||||
x-model="stepModal.form.label"
|
||||
maxlength="255"
|
||||
class="w-full border border-gray-300 dark:border-gray-600 rounded-md px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 dark:bg-gray-700 dark:text-white"
|
||||
placeholder="Override the default step name"
|
||||
placeholder="{{ _('pipelines.step_label_placeholder') }}"
|
||||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
@@ -400,7 +400,7 @@
|
||||
x-model="stepModal.form.config.force_cloud_ocr"
|
||||
class="rounded border-gray-300 text-blue-600 focus:ring-blue-400"
|
||||
/>
|
||||
<span class="text-sm text-gray-700 dark:text-gray-300">Force cloud OCR (skip local text extraction)</span>
|
||||
<span class="text-sm text-gray-700 dark:text-gray-300">{{ _("pipelines.force_cloud_ocr_label") }}</span>
|
||||
</label>
|
||||
</template>
|
||||
|
||||
@@ -408,14 +408,14 @@
|
||||
<template x-if="stepModal.form.step_type === 'ocr'">
|
||||
<div>
|
||||
<label for="ocrLanguage" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
||||
OCR Language
|
||||
{{ _("pipelines.ocr_language_label") }}
|
||||
</label>
|
||||
<select
|
||||
id="ocrLanguage"
|
||||
x-model="stepModal.form.config.ocr_language"
|
||||
class="w-full border border-gray-300 dark:border-gray-600 rounded-md px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 dark:bg-gray-700 dark:text-white"
|
||||
>
|
||||
<option value="auto">Auto (use system default)</option>
|
||||
<option value="auto">{{ _("pipelines.ocr_auto") }}</option>
|
||||
<option value="ara">Arabic</option>
|
||||
<option value="chi_sim">Chinese (Simplified)</option>
|
||||
<option value="chi_tra">Chinese (Traditional)</option>
|
||||
@@ -446,7 +446,7 @@
|
||||
<option value="vie">Vietnamese</option>
|
||||
</select>
|
||||
<p class="mt-1 text-xs text-gray-400">
|
||||
Overrides the global language setting for Tesseract/EasyOCR. Azure and Mistral auto-detect the language.
|
||||
{{ _("pipelines.ocr_language_hint") }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
@@ -458,7 +458,7 @@
|
||||
x-model="stepModal.form.enabled"
|
||||
class="rounded border-gray-300 text-blue-600 focus:ring-blue-400"
|
||||
/>
|
||||
<span class="text-sm text-gray-700 dark:text-gray-300">Enabled</span>
|
||||
<span class="text-sm text-gray-700 dark:text-gray-300">{{ _("pipelines.enabled_label") }}</span>
|
||||
</label>
|
||||
|
||||
<!-- Error -->
|
||||
@@ -471,7 +471,7 @@
|
||||
@click="closeStepModal()"
|
||||
class="px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded-md hover:bg-gray-50"
|
||||
style="min-height:44px;"
|
||||
>Cancel</button>
|
||||
>{{ _("common.cancel") }}</button>
|
||||
<button
|
||||
type="submit"
|
||||
:disabled="stepModal.saving"
|
||||
@@ -515,13 +515,13 @@
|
||||
@click="confirmModal.open = false"
|
||||
class="px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded-md hover:bg-gray-50"
|
||||
style="min-height:44px;"
|
||||
>Cancel</button>
|
||||
>{{ _("common.cancel") }}</button>
|
||||
<button
|
||||
type="button"
|
||||
@click="confirmModal.action(); confirmModal.open = false"
|
||||
class="px-4 py-2 text-sm font-medium text-white bg-red-600 hover:bg-red-700 rounded-md"
|
||||
style="min-height:44px;"
|
||||
>Delete</button>
|
||||
>{{ _("common.delete") }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user