feat: Runtime configuration and Docker deployment improvements
Frontend: - Add runtime configuration service for deployment-time API URL injection - Create docker-entrypoint.sh to generate config.json from environment variables - Update ApiService, ApprovalService, and DocumentViewer to use RuntimeConfigService - Add APP_INITIALIZER to load runtime config before app starts Backend: - Fix init-blockchain.js to properly quote mnemonic phrases in .env file - Improve docker-entrypoint.sh with health checks and better error handling Docker: - Add API_BASE_URL environment variable to frontend container - Update docker-compose.yml with clear documentation for remote deployment - Reorganize .env.example with clear categories (REQUIRED FOR REMOTE, PRODUCTION, AUTO-GENERATED) Workflow fixes: - Fix DepartmentApproval interface to match backend schema - Fix stage transformation for 0-indexed stageOrder - Fix workflow list to show correct stage count from definition.stages Cleanup: - Move development artifacts to .trash directory - Remove root-level package.json (was only for utility scripts) - Add .trash/ to .gitignore
This commit is contained in:
@@ -304,7 +304,7 @@ export class WorkflowFormComponent implements OnInit {
|
||||
private loadDepartments(): void {
|
||||
this.departmentService.getDepartments(1, 100).subscribe({
|
||||
next: (response) => {
|
||||
this.departments.set(response.data);
|
||||
this.departments.set(response?.data ?? []);
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -322,14 +322,19 @@ export class WorkflowFormComponent implements OnInit {
|
||||
});
|
||||
|
||||
this.stagesArray.clear();
|
||||
workflow.stages.forEach((stage) => {
|
||||
const stages = workflow.definition?.stages || [];
|
||||
stages.forEach((stage) => {
|
||||
// Find department by code to get departmentId
|
||||
const dept = this.departments().find(d =>
|
||||
d.code === stage.requiredApprovals?.[0]?.departmentCode
|
||||
);
|
||||
this.stagesArray.push(
|
||||
this.fb.group({
|
||||
id: [stage.id],
|
||||
name: [stage.name, Validators.required],
|
||||
departmentId: [stage.departmentId, Validators.required],
|
||||
order: [stage.order],
|
||||
isRequired: [stage.isRequired],
|
||||
id: [stage.stageId],
|
||||
name: [stage.stageName, Validators.required],
|
||||
departmentId: [dept?.id || '', Validators.required],
|
||||
order: [stage.stageOrder],
|
||||
isRequired: [stage.metadata?.['isRequired'] ?? true],
|
||||
})
|
||||
);
|
||||
});
|
||||
@@ -414,18 +419,30 @@ export class WorkflowFormComponent implements OnInit {
|
||||
const departmentId = currentUser?.departmentId ||
|
||||
(values.stages[0]?.departmentId) || '';
|
||||
|
||||
const dto = {
|
||||
// Transform to backend DTO format
|
||||
const dto: any = {
|
||||
name: normalizeWhitespace(values.name),
|
||||
description: normalizeWhitespace(values.description) || undefined,
|
||||
workflowType: values.workflowType!,
|
||||
departmentId: departmentId,
|
||||
stages: values.stages.map((s, i) => ({
|
||||
id: s.id || `stage-${i + 1}`,
|
||||
name: normalizeWhitespace(s.name) || `Stage ${i + 1}`,
|
||||
departmentId: s.departmentId || '',
|
||||
isRequired: s.isRequired ?? true,
|
||||
order: i + 1,
|
||||
})),
|
||||
stages: values.stages.map((s, i) => {
|
||||
const department = this.departments().find(d => d.id === s.departmentId);
|
||||
return {
|
||||
stageId: s.id || `stage-${i + 1}`,
|
||||
stageName: normalizeWhitespace(s.name) || `Stage ${i + 1}`,
|
||||
stageOrder: i, // Backend expects 0-indexed
|
||||
executionType: 'SEQUENTIAL' as const,
|
||||
requiredApprovals: [{
|
||||
departmentCode: department?.code || '',
|
||||
departmentName: department?.name || 'Unknown',
|
||||
canDelegate: false,
|
||||
}],
|
||||
completionCriteria: 'ALL' as const,
|
||||
rejectionHandling: 'FAIL_REQUEST' as const,
|
||||
metadata: {
|
||||
isRequired: s.isRequired ?? true,
|
||||
},
|
||||
};
|
||||
}),
|
||||
};
|
||||
|
||||
const action$ = this.isEditMode()
|
||||
|
||||
Reference in New Issue
Block a user