@smartnet360/svelte-components 0.0.142 → 0.0.144

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.
Files changed (37) hide show
  1. package/dist/apps/antenna-tools/components/AntennaControls.svelte +14 -6
  2. package/dist/apps/antenna-tools/components/AntennaTools.svelte +6 -5
  3. package/dist/core/Auth/auth.svelte.js +72 -39
  4. package/dist/core/Auth/config.d.ts +1 -0
  5. package/dist/core/Auth/config.js +3 -4
  6. package/dist/map-v3/demo/DemoMap.svelte +3 -1
  7. package/dist/map-v3/features/custom/components/CustomCellSetManager.svelte +205 -14
  8. package/dist/map-v3/features/custom/components/CustomCellSetManager.svelte.d.ts +3 -0
  9. package/dist/map-v3/features/custom/components/ServerSetBrowser.svelte +398 -0
  10. package/dist/map-v3/features/custom/components/ServerSetBrowser.svelte.d.ts +22 -0
  11. package/dist/map-v3/features/custom/components/index.d.ts +1 -0
  12. package/dist/map-v3/features/custom/components/index.js +1 -0
  13. package/dist/map-v3/features/custom/db/custom-sets-api.d.ts +65 -0
  14. package/dist/map-v3/features/custom/db/custom-sets-api.js +220 -0
  15. package/dist/map-v3/features/custom/db/custom-sets-repository.d.ts +77 -0
  16. package/dist/map-v3/features/custom/db/custom-sets-repository.js +195 -0
  17. package/dist/map-v3/features/custom/db/index.d.ts +10 -0
  18. package/dist/map-v3/features/custom/db/index.js +9 -0
  19. package/dist/map-v3/features/custom/db/schema.sql +102 -0
  20. package/dist/map-v3/features/custom/db/types.d.ts +95 -0
  21. package/dist/map-v3/features/custom/db/types.js +95 -0
  22. package/dist/map-v3/features/custom/index.d.ts +2 -0
  23. package/dist/map-v3/features/custom/index.js +2 -0
  24. package/dist/map-v3/features/custom/logic/csv-parser.d.ts +12 -1
  25. package/dist/map-v3/features/custom/logic/csv-parser.js +54 -16
  26. package/dist/map-v3/features/custom/logic/tree-adapter.js +5 -3
  27. package/dist/map-v3/features/custom/stores/custom-cell-sets.svelte.d.ts +5 -1
  28. package/dist/map-v3/features/custom/stores/custom-cell-sets.svelte.js +6 -3
  29. package/dist/shared/csv-import/ColumnMapper.svelte +194 -0
  30. package/dist/shared/csv-import/ColumnMapper.svelte.d.ts +22 -0
  31. package/dist/shared/csv-import/column-detector.d.ts +58 -0
  32. package/dist/shared/csv-import/column-detector.js +228 -0
  33. package/dist/shared/csv-import/index.d.ts +10 -0
  34. package/dist/shared/csv-import/index.js +12 -0
  35. package/dist/shared/csv-import/types.d.ts +67 -0
  36. package/dist/shared/csv-import/types.js +70 -0
  37. package/package.json +1 -1
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Shared CSV Import - Column Detector
3
+ *
4
+ * Auto-detects column mappings based on header names.
5
+ * Uses expandable alias maps for flexible matching.
6
+ */
7
+ import type { ColumnMapping, StandardFieldType, ImportFieldsConfig, ImportMode } from './types';
8
+ /**
9
+ * Alias map for auto-detecting column types
10
+ * Add new aliases here to expand recognition
11
+ */
12
+ export declare const COLUMN_ALIASES: Record<StandardFieldType, string[]>;
13
+ /**
14
+ * Find the best matching field type for a column header
15
+ */
16
+ export declare function detectFieldType(header: string): StandardFieldType | null;
17
+ /**
18
+ * Auto-detect column mapping from headers
19
+ * Returns suggested mapping based on alias matching
20
+ */
21
+ export declare function detectColumnMapping(headers: string[], fieldsConfig: ImportFieldsConfig): ColumnMapping;
22
+ /**
23
+ * Validate that all required fields are mapped
24
+ */
25
+ export declare function validateMapping(mapping: ColumnMapping, fieldsConfig: ImportFieldsConfig): {
26
+ valid: boolean;
27
+ missing: string[];
28
+ };
29
+ /**
30
+ * Detect the most likely import mode based on headers
31
+ * Returns 'point' if lat/lon found, 'site' if site-related, otherwise 'cell'
32
+ */
33
+ export declare function detectImportMode(headers: string[]): ImportMode;
34
+ /**
35
+ * Auto-detect import mode and get initial mapping
36
+ */
37
+ export declare function autoDetectImport(headers: string[]): {
38
+ mode: ImportMode;
39
+ mapping: ColumnMapping;
40
+ fieldsConfig: ImportFieldsConfig;
41
+ };
42
+ /**
43
+ * Detect delimiter from CSV content
44
+ */
45
+ export declare function detectDelimiter(headerLine: string): ',' | ';';
46
+ /**
47
+ * Parse CSV header line and return headers array
48
+ */
49
+ export declare function parseHeaderLine(line: string, delimiter: ',' | ';'): string[];
50
+ /**
51
+ * Get CSV headers and suggested mapping
52
+ */
53
+ export declare function analyzeCSVHeaders(csvContent: string, fieldsConfig: ImportFieldsConfig): {
54
+ headers: string[];
55
+ delimiter: ',' | ';';
56
+ suggestedMapping: ColumnMapping;
57
+ rowCount: number;
58
+ };
@@ -0,0 +1,228 @@
1
+ /**
2
+ * Shared CSV Import - Column Detector
3
+ *
4
+ * Auto-detects column mappings based on header names.
5
+ * Uses expandable alias maps for flexible matching.
6
+ */
7
+ import { getFieldsForMode } from './types';
8
+ /**
9
+ * Alias map for auto-detecting column types
10
+ * Add new aliases here to expand recognition
11
+ */
12
+ export const COLUMN_ALIASES = {
13
+ // Universal identifiers
14
+ id: [
15
+ 'id', 'cellname', 'cell_name', 'txid', 'tx_id',
16
+ 'site_id', 'siteid', 'site_code', 'sitecode',
17
+ 'name', 'code', 'identifier', 'key', 'cell_id', 'cellid'
18
+ ],
19
+ // Coordinates
20
+ lat: [
21
+ 'lat', 'latitude', 'y', 'y_coord', 'ycoord',
22
+ 'northing', 'north', 'lat_deg', 'latitude_deg'
23
+ ],
24
+ lon: [
25
+ 'lon', 'lng', 'long', 'longitude', 'x', 'x_coord', 'xcoord',
26
+ 'easting', 'east', 'lon_deg', 'longitude_deg'
27
+ ],
28
+ // Grouping
29
+ group: [
30
+ 'customgroup', 'custom_group', 'group', 'category',
31
+ 'type', 'region', 'area', 'zone', 'cluster', 'segment'
32
+ ],
33
+ // Sizing
34
+ sizeFactor: [
35
+ 'sizefactor', 'size_factor', 'size', 'scale', 'weight', 'factor'
36
+ ],
37
+ // Cell-specific
38
+ tech: [
39
+ 'tech', 'technology', 'rat', 'radio', 'system',
40
+ 'network_type', 'networktype', 'access_technology'
41
+ ],
42
+ band: [
43
+ 'band', 'fband', 'frequency_band', 'frequencyband',
44
+ 'freq', 'frequency', 'carrier', 'earfcn', 'arfcn'
45
+ ],
46
+ azimuth: [
47
+ 'azimuth', 'az', 'bearing', 'direction', 'heading',
48
+ 'antenna_azimuth', 'ant_azimuth', 'ant_az'
49
+ ],
50
+ tilt: [
51
+ 'tilt', 'downtilt', 'etilt', 'mtilt', 'electrical_tilt',
52
+ 'mechanical_tilt', 'antenna_tilt', 'ant_tilt'
53
+ ],
54
+ siteId: [
55
+ 'siteid', 'site_id', 'site', 'location_id', 'locationid',
56
+ 'enodeb_id', 'enodebid', 'gnodeb_id', 'gnodebid', 'bts_id'
57
+ ],
58
+ siteName: [
59
+ 'sitename', 'site_name', 'location_name', 'locationname',
60
+ 'site_label', 'sitelabel', 'station_name'
61
+ ],
62
+ status: [
63
+ 'status', 'state', 'cell_status', 'cellstatus',
64
+ 'operational_status', 'op_status', 'active'
65
+ ],
66
+ height: [
67
+ 'height', 'antenna_height', 'ant_height', 'agl',
68
+ 'elevation', 'tower_height', 'mast_height'
69
+ ],
70
+ power: [
71
+ 'power', 'tx_power', 'txpower', 'eirp',
72
+ 'transmit_power', 'output_power', 'pwr'
73
+ ]
74
+ };
75
+ /**
76
+ * Normalize a column header for comparison
77
+ */
78
+ function normalizeHeader(header) {
79
+ return header
80
+ .trim()
81
+ .toLowerCase()
82
+ .replace(/[\s\-\.]/g, '_'); // Normalize separators to underscore
83
+ }
84
+ /**
85
+ * Find the best matching field type for a column header
86
+ */
87
+ export function detectFieldType(header) {
88
+ const normalized = normalizeHeader(header);
89
+ for (const [fieldType, aliases] of Object.entries(COLUMN_ALIASES)) {
90
+ if (aliases.some(alias => normalized === alias || normalized.includes(alias))) {
91
+ return fieldType;
92
+ }
93
+ }
94
+ return null;
95
+ }
96
+ /**
97
+ * Auto-detect column mapping from headers
98
+ * Returns suggested mapping based on alias matching
99
+ */
100
+ export function detectColumnMapping(headers, fieldsConfig) {
101
+ const mapping = {};
102
+ const usedIndices = new Set();
103
+ // Get all field types we're looking for
104
+ const allFields = [...fieldsConfig.required, ...fieldsConfig.optional];
105
+ // First pass: exact matches and strong matches
106
+ for (const field of allFields) {
107
+ const aliases = COLUMN_ALIASES[field.type] || [];
108
+ for (let i = 0; i < headers.length; i++) {
109
+ if (usedIndices.has(i))
110
+ continue;
111
+ const normalized = normalizeHeader(headers[i]);
112
+ // Check for exact match first
113
+ if (aliases.includes(normalized)) {
114
+ mapping[field.type] = i;
115
+ usedIndices.add(i);
116
+ break;
117
+ }
118
+ }
119
+ }
120
+ // Second pass: partial matches for unmapped fields
121
+ for (const field of allFields) {
122
+ if (mapping[field.type] !== undefined)
123
+ continue;
124
+ const aliases = COLUMN_ALIASES[field.type] || [];
125
+ for (let i = 0; i < headers.length; i++) {
126
+ if (usedIndices.has(i))
127
+ continue;
128
+ const normalized = normalizeHeader(headers[i]);
129
+ // Check for partial match
130
+ if (aliases.some(alias => normalized.includes(alias) || alias.includes(normalized))) {
131
+ mapping[field.type] = i;
132
+ usedIndices.add(i);
133
+ break;
134
+ }
135
+ }
136
+ }
137
+ // Set null for any fields not found
138
+ for (const field of allFields) {
139
+ if (mapping[field.type] === undefined) {
140
+ mapping[field.type] = null;
141
+ }
142
+ }
143
+ return mapping;
144
+ }
145
+ /**
146
+ * Validate that all required fields are mapped
147
+ */
148
+ export function validateMapping(mapping, fieldsConfig) {
149
+ const missing = [];
150
+ for (const field of fieldsConfig.required) {
151
+ if (mapping[field.type] === null || mapping[field.type] === undefined) {
152
+ missing.push(field.label);
153
+ }
154
+ }
155
+ return {
156
+ valid: missing.length === 0,
157
+ missing
158
+ };
159
+ }
160
+ /**
161
+ * Detect the most likely import mode based on headers
162
+ * Returns 'point' if lat/lon found, 'site' if site-related, otherwise 'cell'
163
+ */
164
+ export function detectImportMode(headers) {
165
+ const normalizedHeaders = headers.map(h => normalizeHeader(h));
166
+ // Check for lat/lon presence
167
+ const hasLat = normalizedHeaders.some(h => COLUMN_ALIASES.lat.some(alias => h === alias || h.includes(alias)));
168
+ const hasLon = normalizedHeaders.some(h => COLUMN_ALIASES.lon.some(alias => h === alias || h.includes(alias)));
169
+ const hasLatLon = hasLat && hasLon;
170
+ // Check for site-specific headers
171
+ const hasSiteId = normalizedHeaders.some(h => COLUMN_ALIASES.siteId.some(alias => h === alias || h.includes(alias)));
172
+ const hasSiteName = normalizedHeaders.some(h => COLUMN_ALIASES.siteName.some(alias => h === alias || h.includes(alias)));
173
+ // Check for cell-specific headers
174
+ const hasCellId = normalizedHeaders.some(h => ['cellname', 'cell_name', 'cellid', 'cell_id', 'txid', 'tx_id'].some(alias => h === alias || h.includes(alias)));
175
+ // Decision logic:
176
+ // 1. If has lat/lon AND site-specific headers → site mode
177
+ // 2. If has lat/lon AND no cell-specific headers → point mode
178
+ // 3. Otherwise → cell mode (ID resolves against existing cells)
179
+ if (hasLatLon && (hasSiteId || hasSiteName) && !hasCellId) {
180
+ return 'site';
181
+ }
182
+ if (hasLatLon && !hasCellId) {
183
+ return 'point';
184
+ }
185
+ return 'cell';
186
+ }
187
+ /**
188
+ * Auto-detect import mode and get initial mapping
189
+ */
190
+ export function autoDetectImport(headers) {
191
+ const mode = detectImportMode(headers);
192
+ const fieldsConfig = getFieldsForMode(mode);
193
+ const mapping = detectColumnMapping(headers, fieldsConfig);
194
+ return { mode, mapping, fieldsConfig };
195
+ }
196
+ /**
197
+ * Detect delimiter from CSV content
198
+ */
199
+ export function detectDelimiter(headerLine) {
200
+ const commaCount = (headerLine.match(/,/g) || []).length;
201
+ const semicolonCount = (headerLine.match(/;/g) || []).length;
202
+ return semicolonCount > commaCount ? ';' : ',';
203
+ }
204
+ /**
205
+ * Parse CSV header line and return headers array
206
+ */
207
+ export function parseHeaderLine(line, delimiter) {
208
+ // Simple parse (doesn't handle quoted fields with delimiters inside)
209
+ return line.split(delimiter).map(h => h.trim().replace(/^["']|["']$/g, ''));
210
+ }
211
+ /**
212
+ * Get CSV headers and suggested mapping
213
+ */
214
+ export function analyzeCSVHeaders(csvContent, fieldsConfig) {
215
+ const lines = csvContent.trim().split('\n');
216
+ if (lines.length === 0) {
217
+ return { headers: [], delimiter: ',', suggestedMapping: {}, rowCount: 0 };
218
+ }
219
+ const delimiter = detectDelimiter(lines[0]);
220
+ const headers = parseHeaderLine(lines[0], delimiter);
221
+ const suggestedMapping = detectColumnMapping(headers, fieldsConfig);
222
+ return {
223
+ headers,
224
+ delimiter,
225
+ suggestedMapping,
226
+ rowCount: lines.length - 1
227
+ };
228
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * CSV Import Module
3
+ *
4
+ * Shared utilities for flexible CSV column mapping.
5
+ * Supports auto-detection of columns via aliases and manual mapping UI.
6
+ */
7
+ export type { StandardFieldType, FieldDefinition, ColumnMapping, ImportFieldsConfig, ImportMode } from './types';
8
+ export { CUSTOM_POINTS_FIELDS, CELL_IMPORT_FIELDS, CELL_MODE_FIELDS, POINT_MODE_FIELDS, SITE_MODE_FIELDS, getFieldsForMode } from './types';
9
+ export { COLUMN_ALIASES, detectColumnMapping, detectImportMode, autoDetectImport, validateMapping, analyzeCSVHeaders } from './column-detector';
10
+ export { default as ColumnMapper } from './ColumnMapper.svelte';
@@ -0,0 +1,12 @@
1
+ /**
2
+ * CSV Import Module
3
+ *
4
+ * Shared utilities for flexible CSV column mapping.
5
+ * Supports auto-detection of columns via aliases and manual mapping UI.
6
+ */
7
+ // Field configurations
8
+ export { CUSTOM_POINTS_FIELDS, CELL_IMPORT_FIELDS, CELL_MODE_FIELDS, POINT_MODE_FIELDS, SITE_MODE_FIELDS, getFieldsForMode } from './types';
9
+ // Column detection utilities
10
+ export { COLUMN_ALIASES, detectColumnMapping, detectImportMode, autoDetectImport, validateMapping, analyzeCSVHeaders } from './column-detector';
11
+ // UI Component
12
+ export { default as ColumnMapper } from './ColumnMapper.svelte';
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Shared CSV Import - Types
3
+ *
4
+ * Reusable types for CSV column mapping across different import features.
5
+ */
6
+ /**
7
+ * Import mode - determines which fields are shown and required
8
+ */
9
+ export type ImportMode = 'cell' | 'point' | 'site';
10
+ /**
11
+ * Standard field types that can be mapped
12
+ */
13
+ export type StandardFieldType = 'id' | 'lat' | 'lon' | 'group' | 'sizeFactor' | 'tech' | 'band' | 'azimuth' | 'tilt' | 'siteId' | 'siteName' | 'status' | 'height' | 'power';
14
+ /**
15
+ * Definition of a field for mapping
16
+ */
17
+ export interface FieldDefinition {
18
+ /** Field type identifier */
19
+ type: StandardFieldType;
20
+ /** Display label for UI */
21
+ label: string;
22
+ /** Whether this field is required */
23
+ required: boolean;
24
+ /** Description/help text */
25
+ description?: string;
26
+ }
27
+ /**
28
+ * Mapping of field types to CSV column indices
29
+ */
30
+ export interface ColumnMapping {
31
+ [fieldType: string]: number | null;
32
+ }
33
+ /**
34
+ * Result of parsing CSV headers
35
+ */
36
+ export interface CsvHeadersResult {
37
+ /** All column headers from CSV */
38
+ headers: string[];
39
+ /** Detected delimiter */
40
+ delimiter: ',' | ';';
41
+ /** Auto-detected column mapping (best guesses) */
42
+ suggestedMapping: ColumnMapping;
43
+ /** Total row count (excluding header) */
44
+ rowCount: number;
45
+ }
46
+ /**
47
+ * Configuration for a specific import context
48
+ */
49
+ export interface ImportFieldsConfig {
50
+ /** Fields that must be mapped */
51
+ required: FieldDefinition[];
52
+ /** Fields that can optionally be mapped */
53
+ optional: FieldDefinition[];
54
+ }
55
+ /**
56
+ * Predefined field configurations for import modes
57
+ */
58
+ /** Cell mode - ID resolves against existing cell data */
59
+ export declare const CELL_MODE_FIELDS: ImportFieldsConfig;
60
+ /** Point mode - creates markers at lat/lon coordinates */
61
+ export declare const POINT_MODE_FIELDS: ImportFieldsConfig;
62
+ /** Site mode - creates site markers at lat/lon */
63
+ export declare const SITE_MODE_FIELDS: ImportFieldsConfig;
64
+ /** Get field config for a given import mode */
65
+ export declare function getFieldsForMode(mode: ImportMode): ImportFieldsConfig;
66
+ export declare const CUSTOM_POINTS_FIELDS: ImportFieldsConfig;
67
+ export declare const CELL_IMPORT_FIELDS: ImportFieldsConfig;
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Shared CSV Import - Types
3
+ *
4
+ * Reusable types for CSV column mapping across different import features.
5
+ */
6
+ /**
7
+ * Predefined field configurations for import modes
8
+ */
9
+ /** Cell mode - ID resolves against existing cell data */
10
+ export const CELL_MODE_FIELDS = {
11
+ required: [
12
+ { type: 'id', label: 'Cell ID', required: true, description: 'e.g. cellName, txId' }
13
+ ],
14
+ optional: [
15
+ { type: 'group', label: 'Group', required: false, description: 'e.g. customGroup, category' },
16
+ { type: 'sizeFactor', label: 'Size', required: false, description: 'e.g. sizeFactor, weight' }
17
+ ]
18
+ };
19
+ /** Point mode - creates markers at lat/lon coordinates */
20
+ export const POINT_MODE_FIELDS = {
21
+ required: [
22
+ { type: 'id', label: 'ID / Name', required: true, description: 'e.g. name, label, id' },
23
+ { type: 'lat', label: 'Latitude', required: true, description: 'e.g. lat, latitude, y' },
24
+ { type: 'lon', label: 'Longitude', required: true, description: 'e.g. lon, lng, longitude, x' }
25
+ ],
26
+ optional: [
27
+ { type: 'group', label: 'Group', required: false, description: 'e.g. category, type' },
28
+ { type: 'sizeFactor', label: 'Size', required: false, description: 'e.g. size, weight' }
29
+ ]
30
+ };
31
+ /** Site mode - creates site markers at lat/lon */
32
+ export const SITE_MODE_FIELDS = {
33
+ required: [
34
+ { type: 'id', label: 'Site ID', required: true, description: 'e.g. siteId, site_id, enodeb_id' },
35
+ { type: 'lat', label: 'Latitude', required: true, description: 'e.g. lat, latitude' },
36
+ { type: 'lon', label: 'Longitude', required: true, description: 'e.g. lon, longitude' }
37
+ ],
38
+ optional: [
39
+ { type: 'siteName', label: 'Site Name', required: false, description: 'e.g. site_name, location' },
40
+ { type: 'group', label: 'Group', required: false, description: 'e.g. region, area' }
41
+ ]
42
+ };
43
+ /** Get field config for a given import mode */
44
+ export function getFieldsForMode(mode) {
45
+ switch (mode) {
46
+ case 'cell': return CELL_MODE_FIELDS;
47
+ case 'point': return POINT_MODE_FIELDS;
48
+ case 'site': return SITE_MODE_FIELDS;
49
+ }
50
+ }
51
+ // Legacy exports for backward compatibility
52
+ export const CUSTOM_POINTS_FIELDS = CELL_MODE_FIELDS;
53
+ export const CELL_IMPORT_FIELDS = {
54
+ required: [
55
+ { type: 'id', label: 'Cell ID', required: true, description: 'Unique cell identifier' },
56
+ { type: 'lat', label: 'Latitude', required: true },
57
+ { type: 'lon', label: 'Longitude', required: true },
58
+ { type: 'azimuth', label: 'Azimuth', required: true, description: 'Antenna direction (0-360°)' }
59
+ ],
60
+ optional: [
61
+ { type: 'siteId', label: 'Site ID', required: false },
62
+ { type: 'siteName', label: 'Site Name', required: false },
63
+ { type: 'tech', label: 'Technology', required: false, description: 'e.g., LTE, NR, GSM' },
64
+ { type: 'band', label: 'Band', required: false, description: 'Frequency band' },
65
+ { type: 'tilt', label: 'Tilt', required: false },
66
+ { type: 'height', label: 'Height', required: false },
67
+ { type: 'power', label: 'Power', required: false },
68
+ { type: 'status', label: 'Status', required: false }
69
+ ]
70
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smartnet360/svelte-components",
3
- "version": "0.0.142",
3
+ "version": "0.0.144",
4
4
  "scripts": {
5
5
  "dev": "vite dev",
6
6
  "build": "vite build && npm run prepack",