cat-documents-ng 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ng-package.json +10 -0
- package/package.json +5 -11
- package/src/Shared/components/confirmation-dialog/confirmation-dialog.component.html +3 -0
- package/src/Shared/components/confirmation-dialog/confirmation-dialog.component.scss +13 -0
- package/src/Shared/components/confirmation-dialog/confirmation-dialog.component.spec.ts +70 -0
- package/src/Shared/components/confirmation-dialog/confirmation-dialog.component.ts +133 -0
- package/src/Shared/components/table-primary/table-primary.component.html +66 -0
- package/src/Shared/components/table-primary/table-primary.component.scss +227 -0
- package/src/Shared/components/table-primary/table-primary.component.spec.ts +23 -0
- package/src/Shared/components/table-primary/table-primary.component.ts +143 -0
- package/src/Shared/components/table-primary/table-primary.model.ts +21 -0
- package/src/Shared/constant/ERROR.ts +55 -0
- package/src/Shared/constant/PERMISSIONS.ts +17 -0
- package/src/Shared/constant/SHARED.ts +936 -0
- package/{Shared/constant/URLS.d.ts → src/Shared/constant/URLS.ts} +31 -25
- package/src/Shared/services/app-config.service.spec.ts +19 -0
- package/src/Shared/services/app-config.service.ts +73 -0
- package/{Shared/services/global-error.handler.d.ts → src/Shared/services/global-error.handler.ts} +11 -9
- package/src/Shared/services/session.service.spec.ts +16 -0
- package/src/Shared/services/session.service.ts +76 -0
- package/src/Shared/shared.module.ts +25 -0
- package/src/lib/document/components/csv-viewer/csv-viewer.component.ts +1 -0
- package/src/lib/document/components/document-actions/document-actions.component.html +59 -0
- package/src/lib/document/components/document-actions/document-actions.component.scss +362 -0
- package/src/lib/document/components/document-actions/document-actions.component.spec.ts +297 -0
- package/src/lib/document/components/document-actions/document-actions.component.ts +163 -0
- package/src/lib/document/components/document-container/document-container.component.html +36 -0
- package/src/lib/document/components/document-container/document-container.component.scss +144 -0
- package/src/lib/document/components/document-container/document-container.component.spec.ts +110 -0
- package/src/lib/document/components/document-container/document-container.component.ts +363 -0
- package/src/lib/document/components/document-content-viewer/document-content-viewer.component.html +332 -0
- package/src/lib/document/components/document-content-viewer/document-content-viewer.component.scss +1877 -0
- package/src/lib/document/components/document-content-viewer/document-content-viewer.component.spec.ts +258 -0
- package/src/lib/document/components/document-content-viewer/document-content-viewer.component.ts +664 -0
- package/src/lib/document/components/document-history/document-history.component.html +96 -0
- package/src/lib/document/components/document-history/document-history.component.scss +392 -0
- package/src/lib/document/components/document-history/document-history.component.spec.ts +93 -0
- package/src/lib/document/components/document-history/document-history.component.ts +373 -0
- package/src/lib/document/components/document-list/document-list.component.html +46 -0
- package/src/lib/document/components/document-list/document-list.component.scss +513 -0
- package/src/lib/document/components/document-list/document-list.component.spec.ts +486 -0
- package/src/lib/document/components/document-list/document-list.component.ts +682 -0
- package/src/lib/document/components/document-list-item/document-list-item.component.html +36 -0
- package/src/lib/document/components/document-list-item/document-list-item.component.scss +34 -0
- package/src/lib/document/components/document-list-item/document-list-item.component.spec.ts +75 -0
- package/src/lib/document/components/document-list-item/document-list-item.component.ts +40 -0
- package/src/lib/document/components/document-search/document-search.component.html +64 -0
- package/src/lib/document/components/document-search/document-search.component.scss +206 -0
- package/src/lib/document/components/document-search/document-search.component.spec.ts +82 -0
- package/src/lib/document/components/document-search/document-search.component.ts +163 -0
- package/src/lib/document/components/document-status/document-status.component.html +31 -0
- package/src/lib/document/components/document-status/document-status.component.scss +192 -0
- package/src/lib/document/components/document-status/document-status.component.spec.ts +23 -0
- package/src/lib/document/components/document-status/document-status.component.ts +87 -0
- package/src/lib/document/components/document-upload/document-upload.component.html +160 -0
- package/src/lib/document/components/document-upload/document-upload.component.scss +235 -0
- package/src/lib/document/components/document-upload/document-upload.component.spec.ts +95 -0
- package/src/lib/document/components/document-upload/document-upload.component.ts +668 -0
- package/src/lib/document/components/document-viewer/document-viewer.component.html +50 -0
- package/src/lib/document/components/document-viewer/document-viewer.component.scss +187 -0
- package/src/lib/document/components/document-viewer/document-viewer.component.spec.ts +79 -0
- package/src/lib/document/components/document-viewer/document-viewer.component.ts +261 -0
- package/src/lib/document/components/document-zoom-controls/document-zoom-controls.component.html +48 -0
- package/src/lib/document/components/document-zoom-controls/document-zoom-controls.component.scss +320 -0
- package/src/lib/document/components/document-zoom-controls/document-zoom-controls.component.spec.ts +59 -0
- package/src/lib/document/components/document-zoom-controls/document-zoom-controls.component.ts +150 -0
- package/src/lib/document/components/documents-menu/documents-menu.component.html +44 -0
- package/src/lib/document/components/documents-menu/documents-menu.component.scss +363 -0
- package/src/lib/document/components/documents-menu/documents-menu.component.spec.ts +23 -0
- package/src/lib/document/components/documents-menu/documents-menu.component.ts +316 -0
- package/src/lib/document/components/folder-block/folder-block.component.html +46 -0
- package/src/lib/document/components/folder-block/folder-block.component.scss +9 -0
- package/src/lib/document/components/folder-block/folder-block.component.spec.ts +70 -0
- package/{lib/document/components/folder-block/folder-block.component.d.ts → src/lib/document/components/folder-block/folder-block.component.ts} +28 -12
- package/src/lib/document/components/folder-container/folder-container.component.html +56 -0
- package/src/lib/document/components/folder-container/folder-container.component.scss +20 -0
- package/src/lib/document/components/folder-container/folder-container.component.spec.ts +27 -0
- package/src/lib/document/components/folder-container/folder-container.component.ts +328 -0
- package/src/lib/document/components/linked-document/linked-document.component.html +23 -0
- package/src/lib/document/components/linked-document/linked-document.component.scss +10 -0
- package/src/lib/document/components/linked-document/linked-document.component.spec.ts +61 -0
- package/src/lib/document/components/linked-document/linked-document.component.ts +49 -0
- package/src/lib/document/components/request-document/request-document.component.html +86 -0
- package/src/lib/document/components/request-document/request-document.component.scss +16 -0
- package/src/lib/document/components/request-document/request-document.component.ts +278 -0
- package/src/lib/document/components/sidebar/sidebar.component.html +75 -0
- package/src/lib/document/components/sidebar/sidebar.component.scss +157 -0
- package/src/lib/document/components/sidebar/sidebar.component.spec.ts +114 -0
- package/src/lib/document/components/sidebar/sidebar.component.ts +223 -0
- package/src/lib/document/components/user-list/user-list.component.html +33 -0
- package/src/lib/document/components/user-list/user-list.component.scss +118 -0
- package/src/lib/document/components/user-list/user-list.component.spec.ts +23 -0
- package/src/lib/document/components/user-list/user-list.component.ts +181 -0
- package/src/lib/document/constant/DOCUMENT_HISTORY.ts +52 -0
- package/src/lib/document/directives/document.directive.ts +32 -0
- package/src/lib/document/directives/permission.directive.spec.ts +0 -0
- package/src/lib/document/directives/permission.directive.ts +72 -0
- package/src/lib/document/document.module.ts +351 -0
- package/{lib/document/models/document-alert.model.d.ts → src/lib/document/models/document-alert.model.ts} +11 -4
- package/src/lib/document/models/document-category.model.ts +30 -0
- package/src/lib/document/models/document-history.model.ts +109 -0
- package/src/lib/document/models/document-list-response.model.ts +37 -0
- package/src/lib/document/models/document-type.model.ts +44 -0
- package/src/lib/document/models/document.model.ts +53 -0
- package/{lib/document/models/folder.model.d.ts → src/lib/document/models/folder.model.ts} +10 -4
- package/src/lib/document/models/status-data.model.ts +31 -0
- package/src/lib/document/models/uploaded-file-response.model.ts +7 -0
- package/src/lib/document/models/user-list.model.ts +10 -0
- package/src/lib/document/services/csv-parser.service.spec.ts +97 -0
- package/src/lib/document/services/csv-parser.service.ts +303 -0
- package/src/lib/document/services/document-actions.service.ts +125 -0
- package/src/lib/document/services/document-content-type.service.ts +193 -0
- package/src/lib/document/services/document-history-style.service.ts +138 -0
- package/src/lib/document/services/document-history.service.ts +129 -0
- package/src/lib/document/services/document-http.service.spec.ts +119 -0
- package/src/lib/document/services/document-http.service.ts +497 -0
- package/src/lib/document/services/document-list.service.ts +195 -0
- package/src/lib/document/services/document-menu.service.ts +277 -0
- package/src/lib/document/services/document-scroll.service.ts +138 -0
- package/src/lib/document/services/document-severity.service.ts +98 -0
- package/src/lib/document/services/document-table-builder.service.ts +82 -0
- package/src/lib/document/services/document-upload-business.service.ts +326 -0
- package/src/lib/document/services/document-upload-data.service.ts +82 -0
- package/src/lib/document/services/document-upload-form.service.ts +149 -0
- package/src/lib/document/services/document-upload.service.spec.ts +99 -0
- package/src/lib/document/services/document-upload.service.ts +209 -0
- package/src/lib/document/services/document-viewer.service.ts +279 -0
- package/src/lib/document/services/document-zoom.service.spec.ts +56 -0
- package/src/lib/document/services/document-zoom.service.ts +164 -0
- package/src/lib/document/services/document.service.ts +356 -0
- package/src/lib/document/services/eml-parser.service.ts +444 -0
- package/src/lib/document/services/excel-parser.service.spec.ts +66 -0
- package/src/lib/document/services/excel-parser.service.ts +483 -0
- package/src/lib/document/services/file-format.service.spec.ts +16 -0
- package/src/lib/document/services/file-format.service.ts +63 -0
- package/src/lib/document/services/status-calculator.service.ts +44 -0
- package/src/lib/document/services/user-list.service.ts +77 -0
- package/src/lib/document/state/document.query.ts +378 -0
- package/{lib/document/state/document.service.d.ts → src/lib/document/state/document.service.ts} +46 -15
- package/src/lib/document/state/document.state.ts +100 -0
- package/src/lib/document/state/document.store.ts +200 -0
- package/{public-api.d.ts → src/public-api.ts} +4 -0
- package/tsconfig.lib.json +15 -0
- package/tsconfig.lib.prod.json +11 -0
- package/tsconfig.spec.json +15 -0
- package/Shared/components/confirmation-dialog/confirmation-dialog.component.d.ts +0 -44
- package/Shared/components/table-primary/table-primary.component.d.ts +0 -31
- package/Shared/components/table-primary/table-primary.model.d.ts +0 -19
- package/Shared/constant/ERROR.d.ts +0 -52
- package/Shared/constant/SHARED.d.ts +0 -546
- package/Shared/services/app-config.service.d.ts +0 -51
- package/Shared/services/session.service.d.ts +0 -46
- package/Shared/shared.module.d.ts +0 -14
- package/fesm2022/cat-documents-ng.mjs +0 -11392
- package/fesm2022/cat-documents-ng.mjs.map +0 -1
- package/index.d.ts +0 -5
- package/lib/document/components/document-actions/document-actions.component.d.ts +0 -78
- package/lib/document/components/document-container/document-container.component.d.ts +0 -162
- package/lib/document/components/document-content-viewer/document-content-viewer.component.d.ts +0 -291
- package/lib/document/components/document-history/document-history.component.d.ts +0 -160
- package/lib/document/components/document-list/document-list.component.d.ts +0 -299
- package/lib/document/components/document-list-item/document-list-item.component.d.ts +0 -28
- package/lib/document/components/document-search/document-search.component.d.ts +0 -77
- package/lib/document/components/document-status/document-status.component.d.ts +0 -24
- package/lib/document/components/document-upload/document-upload.component.d.ts +0 -321
- package/lib/document/components/document-viewer/document-viewer.component.d.ts +0 -137
- package/lib/document/components/document-zoom-controls/document-zoom-controls.component.d.ts +0 -33
- package/lib/document/components/documents-menu/documents-menu.component.d.ts +0 -110
- package/lib/document/components/folder-container/folder-container.component.d.ts +0 -162
- package/lib/document/components/linked-document/linked-document.component.d.ts +0 -39
- package/lib/document/components/request-document/request-document.component.d.ts +0 -69
- package/lib/document/components/sidebar/sidebar.component.d.ts +0 -109
- package/lib/document/components/user-list/user-list.component.d.ts +0 -34
- package/lib/document/constant/DOCUMENT_HISTORY.d.ts +0 -41
- package/lib/document/directives/document.directive.d.ts +0 -20
- package/lib/document/directives/permission.directive.d.ts +0 -38
- package/lib/document/document.module.d.ts +0 -60
- package/lib/document/models/document-category.model.d.ts +0 -24
- package/lib/document/models/document-history.model.d.ts +0 -94
- package/lib/document/models/document-list-response.model.d.ts +0 -33
- package/lib/document/models/document-type.model.d.ts +0 -37
- package/lib/document/models/document.model.d.ts +0 -44
- package/lib/document/models/status-data.model.d.ts +0 -27
- package/lib/document/models/uploaded-file-response.model.d.ts +0 -7
- package/lib/document/models/user-list.model.d.ts +0 -8
- package/lib/document/services/csv-parser.service.d.ts +0 -88
- package/lib/document/services/document-actions.service.d.ts +0 -48
- package/lib/document/services/document-content-type.service.d.ts +0 -85
- package/lib/document/services/document-history-style.service.d.ts +0 -34
- package/lib/document/services/document-history.service.d.ts +0 -42
- package/lib/document/services/document-http.service.d.ts +0 -179
- package/lib/document/services/document-list.service.d.ts +0 -74
- package/lib/document/services/document-menu.service.d.ts +0 -122
- package/lib/document/services/document-scroll.service.d.ts +0 -55
- package/lib/document/services/document-table-builder.service.d.ts +0 -38
- package/lib/document/services/document-upload-business.service.d.ts +0 -107
- package/lib/document/services/document-upload-data.service.d.ts +0 -40
- package/lib/document/services/document-upload-form.service.d.ts +0 -41
- package/lib/document/services/document-upload.service.d.ts +0 -99
- package/lib/document/services/document-viewer.service.d.ts +0 -97
- package/lib/document/services/document-zoom.service.d.ts +0 -81
- package/lib/document/services/document.service.d.ts +0 -161
- package/lib/document/services/eml-parser.service.d.ts +0 -116
- package/lib/document/services/excel-parser.service.d.ts +0 -169
- package/lib/document/services/file-format.service.d.ts +0 -34
- package/lib/document/services/status-calculator.service.d.ts +0 -20
- package/lib/document/services/user-list.service.d.ts +0 -29
- package/lib/document/state/document.query.d.ts +0 -243
- package/lib/document/state/document.state.d.ts +0 -61
- package/lib/document/state/document.store.d.ts +0 -56
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
import { SHARED } from '../../../Shared/constant/SHARED';
|
|
3
|
+
|
|
4
|
+
export interface CsvRowData {
|
|
5
|
+
cells: Array<{
|
|
6
|
+
value: string;
|
|
7
|
+
isHeader?: boolean;
|
|
8
|
+
style?: any;
|
|
9
|
+
}>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface ParsedCsvData {
|
|
13
|
+
headers: string[];
|
|
14
|
+
rows: string[][];
|
|
15
|
+
styledData: CsvRowData[];
|
|
16
|
+
totalRows: number;
|
|
17
|
+
totalColumns: number;
|
|
18
|
+
hasHeaders: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@Injectable({
|
|
22
|
+
providedIn: 'root'
|
|
23
|
+
})
|
|
24
|
+
export class CsvParserService {
|
|
25
|
+
|
|
26
|
+
constructor() { }
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Parses CSV data from a string
|
|
30
|
+
* @param csvContent - The CSV content as a string
|
|
31
|
+
* @param options - Parsing options
|
|
32
|
+
* @returns Parsed CSV data
|
|
33
|
+
*/
|
|
34
|
+
parseCsvData(csvContent: string, options: {
|
|
35
|
+
delimiter?: string;
|
|
36
|
+
hasHeaders?: boolean;
|
|
37
|
+
maxRows?: number;
|
|
38
|
+
} = {}): ParsedCsvData {
|
|
39
|
+
const {
|
|
40
|
+
delimiter = ',',
|
|
41
|
+
hasHeaders = true,
|
|
42
|
+
maxRows = 1000
|
|
43
|
+
} = options;
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
// Split content into lines and filter out empty lines
|
|
47
|
+
const lines = csvContent
|
|
48
|
+
.split('\n')
|
|
49
|
+
.map(line => line.trim())
|
|
50
|
+
.filter(line => line.length > 0);
|
|
51
|
+
|
|
52
|
+
if (lines.length === 0) {
|
|
53
|
+
return this.createEmptyCsvData();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Parse each line
|
|
57
|
+
const parsedRows: string[][] = [];
|
|
58
|
+
let headers: string[] = [];
|
|
59
|
+
|
|
60
|
+
lines.forEach((line, index) => {
|
|
61
|
+
if (index >= maxRows) return;
|
|
62
|
+
|
|
63
|
+
const row = this.parseCsvLine(line, delimiter);
|
|
64
|
+
if (row.length > 0) {
|
|
65
|
+
parsedRows.push(row);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Extract headers if specified
|
|
70
|
+
if (hasHeaders && parsedRows.length > 0) {
|
|
71
|
+
headers = parsedRows[0];
|
|
72
|
+
parsedRows.splice(0, 1); // Remove header row from data
|
|
73
|
+
} else if (parsedRows.length > 0) {
|
|
74
|
+
// Generate default headers if none provided
|
|
75
|
+
headers = parsedRows[0].map((_, index) => `Column ${index + 1}`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Create styled data for display
|
|
79
|
+
const styledData = this.createStyledData(headers, parsedRows, hasHeaders);
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
headers,
|
|
83
|
+
rows: parsedRows,
|
|
84
|
+
styledData,
|
|
85
|
+
totalRows: parsedRows.length,
|
|
86
|
+
totalColumns: headers.length,
|
|
87
|
+
hasHeaders
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
} catch (error) {
|
|
91
|
+
console.error('Error parsing CSV data:', error);
|
|
92
|
+
return this.createEmptyCsvData();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Parses a single CSV line with proper handling of quoted fields
|
|
98
|
+
* @param line - Single CSV line
|
|
99
|
+
* @param delimiter - Field delimiter
|
|
100
|
+
* @returns Array of field values
|
|
101
|
+
*/
|
|
102
|
+
private parseCsvLine(line: string, delimiter: string): string[] {
|
|
103
|
+
const result: string[] = [];
|
|
104
|
+
let current = '';
|
|
105
|
+
let inQuotes = false;
|
|
106
|
+
let i = 0;
|
|
107
|
+
|
|
108
|
+
while (i < line.length) {
|
|
109
|
+
const char = line[i];
|
|
110
|
+
|
|
111
|
+
if (char === '"') {
|
|
112
|
+
if (inQuotes && line[i + 1] === '"') {
|
|
113
|
+
// Escaped quote
|
|
114
|
+
current += '"';
|
|
115
|
+
i += 2;
|
|
116
|
+
} else {
|
|
117
|
+
// Toggle quote state
|
|
118
|
+
inQuotes = !inQuotes;
|
|
119
|
+
i++;
|
|
120
|
+
}
|
|
121
|
+
} else if (char === delimiter && !inQuotes) {
|
|
122
|
+
// End of field
|
|
123
|
+
result.push(current.trim());
|
|
124
|
+
current = '';
|
|
125
|
+
i++;
|
|
126
|
+
} else {
|
|
127
|
+
current += char;
|
|
128
|
+
i++;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Add the last field
|
|
133
|
+
result.push(current.trim());
|
|
134
|
+
|
|
135
|
+
return result;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Creates styled data for display in tables
|
|
140
|
+
* @param headers - Column headers
|
|
141
|
+
* @param rows - Data rows
|
|
142
|
+
* @param hasHeaders - Whether the data has headers
|
|
143
|
+
* @returns Styled data array
|
|
144
|
+
*/
|
|
145
|
+
private createStyledData(headers: string[], rows: string[][], hasHeaders: boolean): CsvRowData[] {
|
|
146
|
+
const styledData: CsvRowData[] = [];
|
|
147
|
+
|
|
148
|
+
// Add header row if headers exist
|
|
149
|
+
if (hasHeaders && headers.length > 0) {
|
|
150
|
+
styledData.push({
|
|
151
|
+
cells: headers.map(header => ({
|
|
152
|
+
value: header,
|
|
153
|
+
isHeader: true,
|
|
154
|
+
style: { fontWeight: 'bold', backgroundColor: '#f8f9fa' }
|
|
155
|
+
}))
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Add data rows
|
|
160
|
+
rows.forEach(row => {
|
|
161
|
+
styledData.push({
|
|
162
|
+
cells: row.map((cell, index) => ({
|
|
163
|
+
value: cell || '',
|
|
164
|
+
isHeader: false,
|
|
165
|
+
style: {}
|
|
166
|
+
}))
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
return styledData;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Creates empty CSV data structure
|
|
175
|
+
* @returns Empty CSV data
|
|
176
|
+
*/
|
|
177
|
+
private createEmptyCsvData(): ParsedCsvData {
|
|
178
|
+
return {
|
|
179
|
+
headers: [],
|
|
180
|
+
rows: [],
|
|
181
|
+
styledData: [],
|
|
182
|
+
totalRows: 0,
|
|
183
|
+
totalColumns: 0,
|
|
184
|
+
hasHeaders: false
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Validates CSV content
|
|
190
|
+
* @param csvContent - CSV content to validate
|
|
191
|
+
* @returns Validation result
|
|
192
|
+
*/
|
|
193
|
+
validateCsvContent(csvContent: string): { isValid: boolean; errors: string[] } {
|
|
194
|
+
const errors: string[] = [];
|
|
195
|
+
|
|
196
|
+
if (!csvContent || csvContent.trim().length === 0) {
|
|
197
|
+
errors.push('CSV content is empty');
|
|
198
|
+
return { isValid: false, errors };
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const lines = csvContent.split('\n').filter(line => line.trim().length > 0);
|
|
202
|
+
|
|
203
|
+
if (lines.length === 0) {
|
|
204
|
+
errors.push('No valid lines found in CSV');
|
|
205
|
+
return { isValid: false, errors };
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Check for consistent column count
|
|
209
|
+
const columnCounts = lines.map(line => this.countColumns(line));
|
|
210
|
+
const firstColumnCount = columnCounts[0];
|
|
211
|
+
|
|
212
|
+
for (let i = 1; i < columnCounts.length; i++) {
|
|
213
|
+
if (columnCounts[i] !== firstColumnCount) {
|
|
214
|
+
errors.push(`Line ${i + 1} has ${columnCounts[i]} columns, expected ${firstColumnCount}`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return {
|
|
219
|
+
isValid: errors.length === 0,
|
|
220
|
+
errors
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Counts columns in a CSV line
|
|
226
|
+
* @param line - CSV line
|
|
227
|
+
* @returns Number of columns
|
|
228
|
+
*/
|
|
229
|
+
private countColumns(line: string): number {
|
|
230
|
+
let count = 0;
|
|
231
|
+
let inQuotes = false;
|
|
232
|
+
let i = 0;
|
|
233
|
+
|
|
234
|
+
while (i < line.length) {
|
|
235
|
+
const char = line[i];
|
|
236
|
+
|
|
237
|
+
if (char === '"') {
|
|
238
|
+
if (inQuotes && line[i + 1] === '"') {
|
|
239
|
+
i += 2;
|
|
240
|
+
} else {
|
|
241
|
+
inQuotes = !inQuotes;
|
|
242
|
+
i++;
|
|
243
|
+
}
|
|
244
|
+
} else if (char === ',' && !inQuotes) {
|
|
245
|
+
count++;
|
|
246
|
+
i++;
|
|
247
|
+
} else {
|
|
248
|
+
i++;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return count + 1; // +1 because we count delimiters, not fields
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Exports data to CSV format
|
|
257
|
+
* @param data - Data to export
|
|
258
|
+
* @param headers - Column headers
|
|
259
|
+
* @param delimiter - Field delimiter
|
|
260
|
+
* @returns CSV string
|
|
261
|
+
*/
|
|
262
|
+
exportToCsv(data: string[][], headers: string[], delimiter: string = ','): string {
|
|
263
|
+
const csvLines: string[] = [];
|
|
264
|
+
|
|
265
|
+
// Add headers if provided
|
|
266
|
+
if (headers && headers.length > 0) {
|
|
267
|
+
csvLines.push(this.escapeCsvField(headers.join(delimiter)));
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Add data rows
|
|
271
|
+
data.forEach(row => {
|
|
272
|
+
const escapedRow = row.map(field => this.escapeCsvField(field));
|
|
273
|
+
csvLines.push(escapedRow.join(delimiter));
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
return csvLines.join('\n');
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Escapes a CSV field value
|
|
281
|
+
* @param field - Field value to escape
|
|
282
|
+
* @returns Escaped field value
|
|
283
|
+
*/
|
|
284
|
+
private escapeCsvField(field: string): string {
|
|
285
|
+
if (field.includes(',') || field.includes('"') || field.includes('\n') || field.includes('\r')) {
|
|
286
|
+
return `"${field.replace(/"/g, '""')}"`;
|
|
287
|
+
}
|
|
288
|
+
return field;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Gets CSV preview (first few rows)
|
|
293
|
+
* @param csvContent - Full CSV content
|
|
294
|
+
* @param maxRows - Maximum number of rows to preview
|
|
295
|
+
* @returns Preview data
|
|
296
|
+
*/
|
|
297
|
+
getCsvPreview(csvContent: string, maxRows: number = 10): ParsedCsvData {
|
|
298
|
+
const lines = csvContent.split('\n').filter(line => line.trim().length > 0);
|
|
299
|
+
const previewContent = lines.slice(0, maxRows + 1).join('\n'); // +1 for header
|
|
300
|
+
|
|
301
|
+
return this.parseCsvData(previewContent, { maxRows });
|
|
302
|
+
}
|
|
303
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
import { SHARED } from '../../../Shared/constant/SHARED';
|
|
3
|
+
|
|
4
|
+
export interface DocumentAction {
|
|
5
|
+
type: typeof SHARED.REJECT_ACTION | typeof SHARED.ACCEPT_ACTION | typeof SHARED.DELETE_ACTION;
|
|
6
|
+
note?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
@Injectable({
|
|
10
|
+
providedIn: 'root'
|
|
11
|
+
})
|
|
12
|
+
export class DocumentActionsService {
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Calculates the card class based on status
|
|
16
|
+
* @param currentStatus - The current status of the document
|
|
17
|
+
* @param statusId - The status ID from API
|
|
18
|
+
* @returns {string} The CSS class for the card
|
|
19
|
+
*/
|
|
20
|
+
calculateCardClass(currentStatus?: string, statusId?: string): string {
|
|
21
|
+
// Use statusId if available, otherwise fall back to currentStatus
|
|
22
|
+
if (statusId) {
|
|
23
|
+
return `status-${statusId}-card`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (!currentStatus) {
|
|
27
|
+
return SHARED.CARD_PENDING;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const status = currentStatus.toLowerCase();
|
|
31
|
+
if (status === SHARED.STATUS_ACCEPTED.toLowerCase() || status === SHARED.STATUS_APPROVED.toLowerCase()) {
|
|
32
|
+
return SHARED.CARD_ACCEPTED;
|
|
33
|
+
} else if (status === SHARED.STATUS_REJECTED_LOWERCASE.toLowerCase() || status === SHARED.STATUS_REJECTED.toLowerCase()) {
|
|
34
|
+
return SHARED.CARD_REJECTED;
|
|
35
|
+
} else {
|
|
36
|
+
return SHARED.CARD_PENDING;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Calculates the reject button class based on status
|
|
42
|
+
* @param currentStatus - The current status of the document
|
|
43
|
+
* @param statusId - The status ID from API
|
|
44
|
+
* @returns {string} The CSS class for the reject button
|
|
45
|
+
*/
|
|
46
|
+
calculateRejectButtonClass(currentStatus?: string, statusId?: string): string {
|
|
47
|
+
// Use statusId if available, otherwise fall back to currentStatus
|
|
48
|
+
if (statusId) {
|
|
49
|
+
return `status-${statusId}-reject`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (!currentStatus) {
|
|
53
|
+
return SHARED.BUTTON_DEFAULT_REJECT;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const status = currentStatus.toLowerCase();
|
|
57
|
+
if (status === SHARED.STATUS_ACCEPTED.toLowerCase() || status === SHARED.STATUS_APPROVED.toLowerCase()) {
|
|
58
|
+
return SHARED.BUTTON_SECONDARY_REJECT;
|
|
59
|
+
} else if (status === SHARED.STATUS_REJECTED_LOWERCASE.toLowerCase() || status === SHARED.STATUS_REJECTED.toLowerCase()) {
|
|
60
|
+
return SHARED.BUTTON_PRIMARY_REJECT;
|
|
61
|
+
} else {
|
|
62
|
+
return SHARED.BUTTON_DEFAULT_REJECT;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Calculates the accept button class based on status
|
|
68
|
+
* @param currentStatus - The current status of the document
|
|
69
|
+
* @param statusId - The status ID from API
|
|
70
|
+
* @returns {string} The CSS class for the accept button
|
|
71
|
+
*/
|
|
72
|
+
calculateAcceptButtonClass(currentStatus?: string, statusId?: string): string {
|
|
73
|
+
// Use statusId if available, otherwise fall back to currentStatus
|
|
74
|
+
if (statusId) {
|
|
75
|
+
return `status-${statusId}-accept`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (!currentStatus) {
|
|
79
|
+
return SHARED.BUTTON_DEFAULT_ACCEPT;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const status = currentStatus.toLowerCase();
|
|
83
|
+
if (status === SHARED.STATUS_ACCEPTED.toLowerCase() || status === SHARED.STATUS_APPROVED.toLowerCase()) {
|
|
84
|
+
return SHARED.BUTTON_PRIMARY_ACCEPT;
|
|
85
|
+
} else if (status === SHARED.STATUS_REJECTED_LOWERCASE.toLowerCase() || status === SHARED.STATUS_REJECTED.toLowerCase()) {
|
|
86
|
+
return SHARED.BUTTON_SECONDARY_ACCEPT;
|
|
87
|
+
} else {
|
|
88
|
+
return SHARED.BUTTON_DEFAULT_ACCEPT;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Creates an accept action
|
|
94
|
+
* @param note - The acceptance note
|
|
95
|
+
* @returns {DocumentAction} The accept action
|
|
96
|
+
*/
|
|
97
|
+
createAcceptAction(note: string): DocumentAction {
|
|
98
|
+
return {
|
|
99
|
+
type: SHARED.ACCEPT_ACTION as 'accept',
|
|
100
|
+
note: note
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Creates a reject action
|
|
106
|
+
* @param note - The rejection note
|
|
107
|
+
* @returns {DocumentAction} The reject action
|
|
108
|
+
*/
|
|
109
|
+
createRejectAction(note: string): DocumentAction {
|
|
110
|
+
return {
|
|
111
|
+
type: SHARED.REJECT_ACTION as 'reject',
|
|
112
|
+
note: note
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Creates a delete action
|
|
118
|
+
* @returns {DocumentAction} The delete action
|
|
119
|
+
*/
|
|
120
|
+
createDeleteAction(): DocumentAction {
|
|
121
|
+
return {
|
|
122
|
+
type: SHARED.DELETE_ACTION as 'delete'
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Service for handling document content types and their mappings.
|
|
5
|
+
* Supports the content types: "xlsx","xls","doc","docx","pdf","jpg","jpeg","odt","csv","png","msg","eml"
|
|
6
|
+
* @class DocumentContentTypeService
|
|
7
|
+
* @typedef {DocumentContentTypeService}
|
|
8
|
+
*/
|
|
9
|
+
@Injectable({
|
|
10
|
+
providedIn: 'root'
|
|
11
|
+
})
|
|
12
|
+
export class DocumentContentTypeService {
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Mapping of file extensions to MIME types
|
|
16
|
+
* @type {Record<string, string>}
|
|
17
|
+
*/
|
|
18
|
+
private readonly extensionToMimeType: Record<string, string> = {
|
|
19
|
+
'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
20
|
+
'xls': 'application/vnd.ms-excel',
|
|
21
|
+
'doc': 'application/msword',
|
|
22
|
+
'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
23
|
+
'pdf': 'application/pdf',
|
|
24
|
+
'jpg': 'image/jpeg',
|
|
25
|
+
'jpeg': 'image/jpeg',
|
|
26
|
+
'odt': 'application/vnd.oasis.opendocument.text',
|
|
27
|
+
'csv': 'text/csv',
|
|
28
|
+
'png': 'image/png',
|
|
29
|
+
'msg': 'application/vnd.ms-outlook',
|
|
30
|
+
'eml': 'message/rfc822'
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Mapping of MIME types to file extensions
|
|
35
|
+
* @type {Record<string, string>}
|
|
36
|
+
*/
|
|
37
|
+
private readonly mimeTypeToExtension: Record<string, string> = {
|
|
38
|
+
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'xlsx',
|
|
39
|
+
'application/vnd.ms-excel': 'xls',
|
|
40
|
+
'application/msword': 'doc',
|
|
41
|
+
'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'docx',
|
|
42
|
+
'application/pdf': 'pdf',
|
|
43
|
+
'image/jpeg': 'jpg',
|
|
44
|
+
'image/jpg': 'jpg',
|
|
45
|
+
'application/vnd.oasis.opendocument.text': 'odt',
|
|
46
|
+
'text/csv': 'csv',
|
|
47
|
+
'image/png': 'png',
|
|
48
|
+
'application/vnd.ms-outlook': 'msg',
|
|
49
|
+
'message/rfc822': 'eml'
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* List of all supported file extensions
|
|
54
|
+
* @type {string[]}
|
|
55
|
+
*/
|
|
56
|
+
readonly supportedExtensions: string[] = [
|
|
57
|
+
'xlsx', 'xls', 'doc', 'docx', 'pdf', 'jpg', 'jpeg', 'odt', 'csv', 'png', 'msg', 'eml'
|
|
58
|
+
];
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* List of all supported MIME types
|
|
62
|
+
* @type {string[]}
|
|
63
|
+
*/
|
|
64
|
+
readonly supportedMimeTypes: string[] = [
|
|
65
|
+
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
66
|
+
'application/vnd.ms-excel',
|
|
67
|
+
'application/msword',
|
|
68
|
+
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
69
|
+
'application/pdf',
|
|
70
|
+
'image/jpeg',
|
|
71
|
+
'image/jpg',
|
|
72
|
+
'application/vnd.oasis.opendocument.text',
|
|
73
|
+
'text/csv',
|
|
74
|
+
'image/png',
|
|
75
|
+
'application/vnd.ms-outlook',
|
|
76
|
+
'message/rfc822'
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Gets the MIME type for a given file extension
|
|
81
|
+
* @param {string} extension - The file extension (with or without dot)
|
|
82
|
+
* @returns {string | undefined} The MIME type or undefined if not supported
|
|
83
|
+
*/
|
|
84
|
+
getMimeType(extension: string): string | undefined {
|
|
85
|
+
const cleanExtension = extension.replace('.', '').toLowerCase();
|
|
86
|
+
return this.extensionToMimeType[cleanExtension];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Gets the file extension for a given MIME type
|
|
91
|
+
* @param {string} mimeType - The MIME type
|
|
92
|
+
* @returns {string | undefined} The file extension or undefined if not supported
|
|
93
|
+
*/
|
|
94
|
+
getExtension(mimeType: string): string | undefined {
|
|
95
|
+
return this.mimeTypeToExtension[mimeType];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Checks if a file extension is supported
|
|
100
|
+
* @param {string} extension - The file extension (with or without dot)
|
|
101
|
+
* @returns {boolean} True if the extension is supported
|
|
102
|
+
*/
|
|
103
|
+
isExtensionSupported(extension: string): boolean {
|
|
104
|
+
const cleanExtension = extension.replace('.', '').toLowerCase();
|
|
105
|
+
return this.supportedExtensions.includes(cleanExtension);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Checks if a MIME type is supported
|
|
110
|
+
* @param {string} mimeType - The MIME type
|
|
111
|
+
* @returns {boolean} True if the MIME type is supported
|
|
112
|
+
*/
|
|
113
|
+
isMimeTypeSupported(mimeType: string): boolean {
|
|
114
|
+
return this.supportedMimeTypes.includes(mimeType);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Gets the file extension from a filename
|
|
119
|
+
* @param {string} filename - The filename
|
|
120
|
+
* @returns {string | undefined} The file extension or undefined if no extension found
|
|
121
|
+
*/
|
|
122
|
+
getExtensionFromFilename(filename: string): string | undefined {
|
|
123
|
+
if (!filename || !filename.includes('.')) {
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
126
|
+
const parts = filename.split('.');
|
|
127
|
+
return parts[parts.length - 1].toLowerCase();
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Gets the MIME type from a filename
|
|
132
|
+
* @param {string} filename - The filename
|
|
133
|
+
* @returns {string | undefined} The MIME type or undefined if not supported
|
|
134
|
+
*/
|
|
135
|
+
getMimeTypeFromFilename(filename: string): string | undefined {
|
|
136
|
+
const extension = this.getExtensionFromFilename(filename);
|
|
137
|
+
return extension ? this.getMimeType(extension) : undefined;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Validates if a file can be uploaded based on its extension
|
|
142
|
+
* @param {string} filename - The filename to validate
|
|
143
|
+
* @returns {boolean} True if the file can be uploaded
|
|
144
|
+
*/
|
|
145
|
+
canUploadFile(filename: string): boolean {
|
|
146
|
+
const extension = this.getExtensionFromFilename(filename);
|
|
147
|
+
return extension ? this.isExtensionSupported(extension) : false;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Gets a human-readable description for a content type
|
|
152
|
+
* @param {string} contentType - The content type (MIME type or extension)
|
|
153
|
+
* @returns {string} Human-readable description
|
|
154
|
+
*/
|
|
155
|
+
getContentTypeDescription(contentType: string): string {
|
|
156
|
+
// Check if it's a MIME type first
|
|
157
|
+
if (this.isMimeTypeSupported(contentType)) {
|
|
158
|
+
const extension = this.getExtension(contentType);
|
|
159
|
+
return this.getExtensionDescription(extension || 'unknown');
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Check if it's an extension
|
|
163
|
+
if (this.isExtensionSupported(contentType)) {
|
|
164
|
+
return this.getExtensionDescription(contentType);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return 'Unknown Document Type';
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Gets a human-readable description for a file extension
|
|
172
|
+
* @param {string} extension - The file extension
|
|
173
|
+
* @returns {string} Human-readable description
|
|
174
|
+
*/
|
|
175
|
+
private getExtensionDescription(extension: string): string {
|
|
176
|
+
const descriptions: Record<string, string> = {
|
|
177
|
+
'xlsx': 'Excel Spreadsheet (XLSX)',
|
|
178
|
+
'xls': 'Excel Spreadsheet (XLS)',
|
|
179
|
+
'doc': 'Word Document (DOC)',
|
|
180
|
+
'docx': 'Word Document (DOCX)',
|
|
181
|
+
'pdf': 'PDF Document',
|
|
182
|
+
'jpg': 'JPEG Image',
|
|
183
|
+
'jpeg': 'JPEG Image',
|
|
184
|
+
'odt': 'OpenDocument Text',
|
|
185
|
+
'csv': 'CSV File',
|
|
186
|
+
'png': 'PNG Image',
|
|
187
|
+
'msg': 'Outlook Message',
|
|
188
|
+
'eml': 'Email Message'
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
return descriptions[extension] || 'Unknown File Type';
|
|
192
|
+
}
|
|
193
|
+
}
|