Skip to content

Commit c04de3d

Browse files
authored
Merge pull request #18 from Star-Academy/frontend/feature/manage-workflows
Frontend/feature/manage workflows to dev branch
2 parents c6cd382 + f3f1933 commit c04de3d

17 files changed

Lines changed: 295 additions & 300 deletions

File tree

etl_frontend/Dockerfile

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@ RUN npm ci
88

99
COPY . .
1010

11-
RUN npm run lint --if-present
12-
13-
RUN npm run build --if-present
11+
RUN npm run build -- --configuration production
1412

1513
FROM nginx:alpine
1614

etl_frontend/nginx.conf

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,42 @@
1+
# server {
2+
# listen 80;
3+
# server_name _;
4+
5+
# root /usr/share/nginx/html;
6+
# index index.html;
7+
8+
# location / {
9+
# try_files $uri $uri/ /index.html;
10+
# }
11+
# }
12+
113
server {
2-
listen 80;
3-
server_name localhost;
14+
listen 443 ssl;
15+
server_name _;
16+
17+
ssl_protocols TLSv1.2 TLSv1.3;
18+
ssl_prefer_server_ciphers on;
19+
ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_265_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA265';
20+
21+
ssl_certificate /etc/nginx/ssl/live/fullchain.pem;
22+
ssl_certificate_key /etc/nginx/ssl/live/privkey.pem;
23+
24+
ssl_session_cache shared:SSL:10m;
25+
ssl_session_timeout 10m;
26+
ssl_session_tickets off;
27+
28+
add_header Strict-Transport-Security "max-age=3156000; includeSubDomains; preload" always;
29+
add_header X-XSS-Protection "1; mode=block";
30+
31+
root /usr/share/nginx/html;
32+
index index.html;
433

5-
root /usr/share/nginx/html;
6-
index index.html;
34+
# MIME types
35+
include /etc/nginx/mime.types;
36+
default_type application/octet-stream;
737

8-
location / {
9-
try_files $uri $uri/ /index.html;
10-
}
38+
# SPA routing
39+
location / {
40+
try_files $uri $uri/ /index.html;
41+
}
1142
}
Lines changed: 39 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,110 +1,54 @@
11
<p-card header="Manage Workflows">
2-
3-
<ng-template pTemplate="header">
4-
</ng-template>
5-
62
<ng-template pTemplate="body">
7-
<div *ngIf="!selectedFileContent && uploadedFileColumns.length === 0">
8-
<p-table
9-
[value]="files"
10-
styleClass="p-datatable-striped p-mt-4"
11-
[tableStyle]="{ 'min-width': '50rem' }"
12-
>
13-
<ng-template pTemplate="header">
14-
<tr>
15-
<th>Flow Name</th>
16-
<th>Last Modified</th>
17-
<th>Actions</th>
18-
</tr>
19-
</ng-template>
20-
<ng-template pTemplate="body" let-file>
21-
<tr>
22-
<td><i class="pi pi-file p-mr-2"></i>{{ file.name }}</td>
23-
<td>{{ file.lastModified }}</td>
24-
<td>
25-
<p-button
26-
icon="pi pi-eye"
27-
styleClass="p-button-rounded p-button-success p-mr-2"
28-
(click)="viewFile(file)"
29-
pTooltip="View Content"
30-
></p-button>
31-
<p-button
32-
icon="pi pi-trash"
33-
styleClass="p-button-rounded p-button-danger"
34-
(click)="deleteFile(file.name)"
35-
pTooltip="Delete File"
36-
></p-button>
37-
</td>
38-
</tr>
39-
</ng-template>
40-
<ng-template pTemplate="emptymessage">
41-
<tr>
42-
<td colspan="4">No files found. Please upload a CSV file.</td>
43-
</tr>
44-
</ng-template>
45-
</p-table>
46-
</div>
47-
</ng-template>
48-
49-
<div *ngIf="selectedFileContent">
50-
<h4>Viewing File Content</h4>
3+
<div class="table-wrapper">
514
<p-table
52-
[value]="selectedFileContent.data"
53-
[columns]="selectedFileContent.headers"
54-
styleClass="p-datatable-gridlines"
55-
>
56-
<ng-template pTemplate="header" let-columns>
57-
<tr>
58-
<th *ngFor="let col of columns">{{ col }}</th>
59-
</tr>
60-
</ng-template>
61-
<ng-template pTemplate="body" let-rowData let-columns="columns">
62-
<tr>
63-
<td *ngFor="let col of columns">
64-
{{ rowData[col] }}
65-
</td>
66-
</tr>
67-
</ng-template>
68-
</p-table>
69-
</div>
70-
71-
<div *ngIf="uploadedFileColumns.length > 0">
72-
<h4>Configure Column Types</h4>
73-
<p>Please assign a data type to each column from your uploaded file.</p>
74-
75-
<p-table
76-
[value]="uploadedFileColumns"
77-
styleClass="p-datatable-striped p-mt-4"
5+
[value]="workflows()"
6+
styleClass="p-datatable-striped"
7+
[tableStyle]="{ 'min-width': '50rem' }"
788
>
799
<ng-template pTemplate="header">
8010
<tr>
81-
<th>Column Header</th>
82-
<th>Data Type</th>
11+
<th>Workflow Name</th>
12+
<th>Description</th>
13+
<th>Created At</th>
14+
<th>Updated At</th>
15+
<th>Status</th>
16+
<th>Actions</th>
8317
</tr>
8418
</ng-template>
85-
<ng-template pTemplate="body" let-column>
19+
<ng-template pTemplate="body" let-workflow>
8620
<tr>
87-
<td>{{ column.header }}</td>
8821
<td>
89-
<p-dropdown
90-
[options]="dbTypes"
91-
[(ngModel)]="column.selectedType"
92-
placeholder="Select a Type"
93-
optionLabel="label"
94-
optionValue="value"
95-
>
96-
</p-dropdown>
22+
<i class="pi pi-file-plus"></i>
23+
{{ workflow.name }}
9724
</td>
25+
<td>{{ workflow.description }}</td>
26+
<td>{{ workflow.createdAt }}</td>
27+
<td>{{ workflow.updatedAt }}</td>
28+
<td>{{ workflow.status }}</td>
29+
<td>
30+
<p-button
31+
icon="pi pi-trash"
32+
styleClass="p-button-rounded p-button-danger p-button-text"
33+
(click)="onDeleteWorkflow(workflow.id, workflow.status)"
34+
pTooltip="Delete Workflow"
35+
[tooltipPosition]="'top'"
36+
></p-button>
37+
<p-button
38+
icon="pi pi-pencil"
39+
styleClass="p-button-rounded p-button-secondary p-button-text"
40+
(click)="onEditWorkflow(workflow.id)"
41+
pTooltip="Edit Workflow"
42+
[tooltipPosition]="'top'"
43+
></p-button>
44+
</td>
45+
</tr>
46+
</ng-template>
47+
<ng-template pTemplate="emptymessage">
48+
<tr style="height: 10rem; font-size: 1.1rem">
49+
<td colspan="4">No Workflow found.</td>
9850
</tr>
9951
</ng-template>
10052
</p-table>
101-
102-
<div class="p-d-flex p-jc-end p-mt-4">
103-
<p-button
104-
label="Confirm Types"
105-
icon="pi pi-check"
106-
(click)="confirmColumnTypes()"
107-
></p-button>
108-
</div>
10953
</div>
110-
</p-card>
54+
</ng-template></p-card>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,18 @@
11
:host {
22
display: flex;
3+
align-items: center;
4+
justify-content: center;
35
padding: 1.5rem;
6+
7+
inline-size: 100%;
8+
9+
.table-wrapper {
10+
inline-size: 100%;
11+
max-block-size: 72vh;
12+
overflow-x: auto;
13+
padding-block-end: 3rem;
14+
overflow-y: auto;
15+
border: 1px solid var(--surface-border);
16+
border-radius: 0.5rem;
17+
}
418
}
Lines changed: 40 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
import { Component } from '@angular/core';
1+
import { Component, computed, effect, OnInit } from '@angular/core';
22
import { MessageService } from 'primeng/api';
3+
import { WorkflowsListStore } from '../../../stores/workflows-list/workflows-list-store.service';
4+
import { WorkflowService } from './service/workflow.service';
35

46
interface FlowsColumn {
57
header: string;
@@ -11,116 +13,51 @@ interface FlowsColumn {
1113
templateUrl: './manage-workflows.component.html',
1214
styleUrl: './manage-workflows.component.scss'
1315
})
14-
export class ManageWorkflowsComponent {
15-
files: any[] = []; // List of all uploaded files
16-
selectedFileContent: { headers: string[], data: any[] } | null = null;
17-
uploadedFileColumns: FlowsColumn[] = [];
18-
19-
// Available database types for column mapping
20-
dbTypes = [
21-
{ label: 'Text', value: 'TEXT' },
22-
{ label: 'Integer', value: 'INTEGER' },
23-
{ label: 'Decimal', value: 'DECIMAL' },
24-
{ label: 'Date', value: 'DATE' },
25-
{ label: 'Boolean', value: 'BOOLEAN' }
26-
];
27-
28-
constructor(private messageService: MessageService) { }
29-
30-
ngOnInit() {
31-
// Mock initial file list (in a real app, you'd fetch this from a server)
32-
this.files = [
33-
{ name: 'flow1', lastModified: '2025-08-15' },
34-
{ name: 'flow2', lastModified: '2025-08-20' },
35-
];
16+
export class ManageWorkflowsComponent implements OnInit{
17+
public readonly workflows = computed(() => this.workflowListStore.vm().workflows);
18+
public readonly isLoading = computed(() => this.workflowListStore.vm().isLoadingWorkflows);
19+
20+
constructor(
21+
private readonly workflowListStore: WorkflowsListStore,
22+
private readonly workflowService: WorkflowService,
23+
private readonly messageService: MessageService,
24+
) {
25+
effect(() => {
26+
console.log(this.workflowListStore.vm())
27+
});
3628
}
3729

38-
// --- FILE LIST ACTIONS ---
30+
public onDeleteWorkflow(workflowId: string, workflowStatus: string) {
31+
if (workflowStatus === 'Running') {
32+
this.messageService.add({
33+
severity: 'error',
34+
summary: 'Workflow is Running. first you need to close it.',
35+
})
3936

40-
/**
41-
* Deletes a file from the list.
42-
* @param fileName The name of the file to delete.
43-
*/
44-
deleteFile(fileName: string) {
45-
this.files = this.files.filter(f => f.name !== fileName);
46-
this.messageService.add({ severity: 'warn', summary: 'Deleted', detail: `File '${fileName}' removed.` });
47-
// If the deleted file was being viewed, clear the view
48-
if (this.selectedFileContent && fileName === 'currently_viewed_file.csv') { // Mock logic
49-
this.selectedFileContent = null;
37+
return;
5038
}
51-
}
52-
53-
/**
54-
* Displays the content of a selected CSV file as a table.
55-
* @param file The file object to view.
56-
*/
57-
viewFile(file: any) {
58-
// In a real app, you would fetch and parse the file content from your server.
59-
// Here we'll just mock the data for demonstration.
60-
this.selectedFileContent = {
61-
headers: ['ID', 'ProductName', 'Price', 'Stock'],
62-
data: [
63-
{ ID: 1, ProductName: 'Laptop', Price: 1200, Stock: 50 },
64-
{ ID: 2, ProductName: 'Mouse', Price: 25, Stock: 300 },
65-
{ ID: 3, ProductName: 'Keyboard', Price: 75, Stock: 150 }
66-
]
67-
};
68-
this.uploadedFileColumns = []; // Hide the upload view
69-
}
70-
71-
// --- FILE UPLOAD AND PROCESSING ---
72-
73-
/**
74-
* Handles the file upload event. Reads the CSV and prepares it for type mapping.
75-
* @param event The upload event containing the file.
76-
*/
77-
onFileUpload(event: any) {
78-
const file = event.files[0];
79-
const reader = new FileReader();
8039

81-
reader.onload = (e) => {
82-
const text = reader.result as string;
83-
const lines = text.split(/\r\n|\n/).filter(line => line.trim() !== ''); // Split lines and remove empty ones
84-
85-
if (lines.length > 0) {
86-
const headers = lines[0].split(',');
87-
this.uploadedFileColumns = headers.map(header => ({
88-
header: header.trim(),
89-
selectedType: 'TEXT' // Default to TEXT
90-
}));
91-
92-
// Add the new file to our list
93-
this.files.push({
94-
name: file.name,
95-
size: `${(file.size / 1024).toFixed(2)} KB`,
96-
lastModified: new Date().toISOString().split('T')[0]
97-
});
98-
99-
this.selectedFileContent = null; // Hide file view
100-
this.messageService.add({ severity: 'success', summary: 'Success', detail: 'File uploaded and parsed.' });
101-
} else {
102-
this.messageService.add({ severity: 'error', summary: 'Error', detail: 'The uploaded file is empty.' });
40+
this.workflowService.deleteWorkflowById(workflowId).subscribe({
41+
next: () => {
42+
this.messageService.add({
43+
severity: 'success',
44+
summary: 'Workflow deleted successfully.',
45+
})
46+
this.workflowListStore.loadWorkflows();
47+
},
48+
error: () => {
49+
this.messageService.add({
50+
severity: 'error',
51+
summary: 'Workflow deleted failed',
52+
})
10353
}
104-
};
105-
106-
reader.onerror = () => {
107-
this.messageService.add({ severity: 'error', summary: 'Error', detail: 'Failed to read file.' });
108-
};
109-
110-
reader.readAsText(file);
54+
})
11155
}
11256

113-
/**
114-
* Finalizes the column type selection.
115-
*/
116-
confirmColumnTypes() {
117-
// In a real app, you would send `this.uploadedFileColumns` to your backend
118-
// to save the mapping and process the data.
119-
console.log('Final column mapping:', this.uploadedFileColumns);
120-
this.messageService.add({ severity: 'info', summary: 'Confirmed', detail: 'Column types have been set.' });
57+
public onEditWorkflow(workflowId: string) {}
12158

122-
// Clear the view after confirming
123-
this.uploadedFileColumns = [];
59+
ngOnInit() {
60+
this.workflowListStore.loadWorkflows();
12461
}
125-
12662
}
63+

0 commit comments

Comments
 (0)