incyclist-services 1.7.54 → 1.7.55
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/lib/cjs/routes/base/parsers/incyclist.js +4 -4
- package/lib/cjs/routes/base/parsers/utils.js +7 -5
- package/lib/cjs/routes/library/service.js +44 -17
- package/lib/cjs/routes/page/service.js +6 -2
- package/lib/esm/routes/base/parsers/incyclist.js +4 -4
- package/lib/esm/routes/base/parsers/utils.js +7 -5
- package/lib/esm/routes/library/service.js +44 -17
- package/lib/esm/routes/page/service.js +6 -2
- package/lib/types/routes/library/types.d.ts +3 -0
- package/package.json +1 -1
|
@@ -30,8 +30,8 @@ class IncyclistXMLParser extends xml_1.XMLParser {
|
|
|
30
30
|
async loadPoints(context) {
|
|
31
31
|
const { data, fileInfo, route } = context;
|
|
32
32
|
const gpxFile = { ...fileInfo };
|
|
33
|
-
const
|
|
34
|
-
const fileName = data['gpx-file-path'] ??
|
|
33
|
+
const xmlBase = fileInfo.base;
|
|
34
|
+
const fileName = data['gpx-file-path'] ?? xmlBase.replace('.xml', '.gpx');
|
|
35
35
|
if (fileName.startsWith('file') || fileName.startsWith('/') || fileName.startsWith('\\') || fileName.startsWith('.')) {
|
|
36
36
|
gpxFile.type = 'file';
|
|
37
37
|
gpxFile.filename = fileName;
|
|
@@ -41,10 +41,10 @@ class IncyclistXMLParser extends xml_1.XMLParser {
|
|
|
41
41
|
gpxFile.url = fileName;
|
|
42
42
|
}
|
|
43
43
|
else if (fileInfo.type === 'url') {
|
|
44
|
-
gpxFile.url = gpxFile.url.replace(
|
|
44
|
+
gpxFile.url = gpxFile.url.replace(xmlBase, fileName);
|
|
45
45
|
}
|
|
46
46
|
else {
|
|
47
|
-
gpxFile.filename = gpxFile.filename.replace(
|
|
47
|
+
gpxFile.filename = gpxFile.filename.replace(xmlBase, fileName);
|
|
48
48
|
}
|
|
49
49
|
try {
|
|
50
50
|
let points;
|
|
@@ -73,7 +73,7 @@ class BinaryReader {
|
|
|
73
73
|
exports.BinaryReader = BinaryReader;
|
|
74
74
|
const getReferencedFileInfo = (info, referenced, scheme = 'file') => {
|
|
75
75
|
if (info.type !== 'url') {
|
|
76
|
-
return buildFromFile(info, referenced
|
|
76
|
+
return buildFromFile(info, referenced);
|
|
77
77
|
}
|
|
78
78
|
if (referenced.url) {
|
|
79
79
|
return referenced.url;
|
|
@@ -81,6 +81,9 @@ const getReferencedFileInfo = (info, referenced, scheme = 'file') => {
|
|
|
81
81
|
if (!referenced.file) {
|
|
82
82
|
return;
|
|
83
83
|
}
|
|
84
|
+
if (referenced.file && info.filename?.startsWith('content://')) {
|
|
85
|
+
return `${info.dir}${info.delimiter}${referenced.file}`;
|
|
86
|
+
}
|
|
84
87
|
const targetFileName = referenced.file;
|
|
85
88
|
const regex = /([\\/])/g;
|
|
86
89
|
if (targetFileName.startsWith('http://') || targetFileName.startsWith('https://')) {
|
|
@@ -97,9 +100,9 @@ const getReferencedFileInfo = (info, referenced, scheme = 'file') => {
|
|
|
97
100
|
}
|
|
98
101
|
};
|
|
99
102
|
exports.getReferencedFileInfo = getReferencedFileInfo;
|
|
100
|
-
const buildFromFile = (info, referenced
|
|
103
|
+
const buildFromFile = (info, referenced) => {
|
|
101
104
|
if (referenced.file) {
|
|
102
|
-
const fileName = info.filename?.replace(info.
|
|
105
|
+
const fileName = info.filename?.replace(info.base, referenced.file);
|
|
103
106
|
return `file:///${fileName}`;
|
|
104
107
|
}
|
|
105
108
|
return referenced.url;
|
|
@@ -107,9 +110,8 @@ const buildFromFile = (info, referenced, scheme = 'file') => {
|
|
|
107
110
|
const buildAbsolutePathTarget = (fileName, info, scheme) => {
|
|
108
111
|
const inputUrl = info.url;
|
|
109
112
|
if (inputUrl.startsWith('incyclist:') || inputUrl.startsWith('file:')) {
|
|
110
|
-
const target = {};
|
|
111
113
|
const parts = inputUrl.split('://');
|
|
112
|
-
const targetPath = parts[1].replace(info.
|
|
114
|
+
const targetPath = parts[1].replace(info.base, fileName);
|
|
113
115
|
return `${scheme}://${targetPath}`;
|
|
114
116
|
}
|
|
115
117
|
};
|
|
@@ -95,7 +95,7 @@ let RouteLibraryScannerService = (() => {
|
|
|
95
95
|
this.importProps = undefined;
|
|
96
96
|
}
|
|
97
97
|
getDisplayProps() {
|
|
98
|
-
return this.importProps;
|
|
98
|
+
return { ...this.importProps };
|
|
99
99
|
}
|
|
100
100
|
importSingle(fileInfo) {
|
|
101
101
|
const observer = new types_1.Observer();
|
|
@@ -125,8 +125,13 @@ let RouteLibraryScannerService = (() => {
|
|
|
125
125
|
this.logError(err, 'scan', { uri: folderInfo.uri });
|
|
126
126
|
observer.emit('error', err.message);
|
|
127
127
|
});
|
|
128
|
-
observer
|
|
128
|
+
observer
|
|
129
|
+
.on('scan-progress', (progress) => {
|
|
129
130
|
this.importProps.scanProgress = progress;
|
|
131
|
+
})
|
|
132
|
+
.on('scan-complete', () => {
|
|
133
|
+
console.log('# scan-complete');
|
|
134
|
+
this.importProps.phase = 'parsing';
|
|
130
135
|
});
|
|
131
136
|
return observer;
|
|
132
137
|
}
|
|
@@ -143,9 +148,18 @@ let RouteLibraryScannerService = (() => {
|
|
|
143
148
|
this.importProps.parseProgress = { parsed, total };
|
|
144
149
|
});
|
|
145
150
|
observer.on('parse-result', (route) => {
|
|
146
|
-
this.importProps.routes.
|
|
151
|
+
const idx = this.importProps.routes.findIndex(r => r.id === route.controlFileUri);
|
|
152
|
+
if (idx !== -1) {
|
|
153
|
+
const observer = this.importProps.routes[idx].observer;
|
|
154
|
+
const displayProps = this.buildRouteDisplayItem(route, observer);
|
|
155
|
+
this.importProps.routes[idx] = displayProps;
|
|
156
|
+
if (observer) {
|
|
157
|
+
observer.emit('updated', displayProps);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
147
160
|
});
|
|
148
161
|
observer.on('parse-complete', () => {
|
|
162
|
+
console.log('# parse-complete');
|
|
149
163
|
this.importProps.phase = 'selecting';
|
|
150
164
|
});
|
|
151
165
|
return observer;
|
|
@@ -283,7 +297,7 @@ let RouteLibraryScannerService = (() => {
|
|
|
283
297
|
const primaryFiles = files.filter((f) => {
|
|
284
298
|
const name = typeof (f) === 'string' ? f : f.name;
|
|
285
299
|
const ext = this.getExtension(name);
|
|
286
|
-
return ext && parsers.isPrimaryExtension(ext);
|
|
300
|
+
return ext && ext !== 'gpx' && parsers.isPrimaryExtension(ext);
|
|
287
301
|
}).map((f) => {
|
|
288
302
|
if (typeof f === 'string') {
|
|
289
303
|
return {
|
|
@@ -299,6 +313,7 @@ let RouteLibraryScannerService = (() => {
|
|
|
299
313
|
if (!this.isCancelled) {
|
|
300
314
|
const routeAnnouncement = await this.buildDiscoveredRoute(file, files, uri, folderName, parsers);
|
|
301
315
|
discoveredCount.value++;
|
|
316
|
+
console.log('added', routeAnnouncement, this.scanResult.length);
|
|
302
317
|
observer.emit('scan-result', routeAnnouncement);
|
|
303
318
|
this.scanResult.push(routeAnnouncement);
|
|
304
319
|
}
|
|
@@ -335,17 +350,29 @@ let RouteLibraryScannerService = (() => {
|
|
|
335
350
|
const service = this.getRouteList();
|
|
336
351
|
const targets = scannedRoutes.filter(r => !r.scanError);
|
|
337
352
|
const total = targets.length;
|
|
353
|
+
targets.forEach(target => {
|
|
354
|
+
const file = this.buildFileInfo(target.controlFileUri, target.format);
|
|
355
|
+
this.importProps.routes.push({
|
|
356
|
+
format: target.format,
|
|
357
|
+
importable: false,
|
|
358
|
+
label: file.base,
|
|
359
|
+
id: target.controlFileUri,
|
|
360
|
+
alreadyImported: false,
|
|
361
|
+
observer: new types_1.Observer()
|
|
362
|
+
});
|
|
363
|
+
});
|
|
364
|
+
observer.emit('parse-start');
|
|
338
365
|
for (let i = 0; i < targets.length; i++) {
|
|
339
366
|
if (this.isCancelled)
|
|
340
367
|
continue;
|
|
341
368
|
const parsed = i + 1;
|
|
342
369
|
const target = targets[i];
|
|
343
370
|
observer.emit('parse-progress', { current: parsed, parsed, total, currentFolder: target.folderName });
|
|
344
|
-
await this._parseTarget(target, service, observer);
|
|
371
|
+
await this._parseTarget(target, service, observer, i);
|
|
345
372
|
}
|
|
346
373
|
observer.emit('parse-complete');
|
|
347
374
|
}
|
|
348
|
-
async _parseTarget(target, service, observer) {
|
|
375
|
+
async _parseTarget(target, service, observer, idx) {
|
|
349
376
|
if (service.existsBySourceUri(target.controlFileUri)) {
|
|
350
377
|
observer.emit('parse-result', {
|
|
351
378
|
alreadyImported: true,
|
|
@@ -465,37 +492,37 @@ let RouteLibraryScannerService = (() => {
|
|
|
465
492
|
}
|
|
466
493
|
}
|
|
467
494
|
buildFileInfo(uri, ext) {
|
|
468
|
-
const
|
|
469
|
-
const dir = uri.slice(0, lastSlash);
|
|
470
|
-
const base = uri.slice(lastSlash + 1);
|
|
471
|
-
const name = base.slice(0, base.length - ext.length - 1);
|
|
495
|
+
const { dir, base, name } = this.getBindings().path.parse(uri);
|
|
472
496
|
return {
|
|
473
|
-
type: '
|
|
497
|
+
type: 'file',
|
|
474
498
|
url: uri,
|
|
475
499
|
filename: uri,
|
|
476
500
|
base,
|
|
477
501
|
name,
|
|
478
502
|
dir,
|
|
479
503
|
ext,
|
|
480
|
-
delimiter: '/'
|
|
504
|
+
delimiter: uri.startsWith('content://') ? '%2F' : '/'
|
|
481
505
|
};
|
|
482
506
|
}
|
|
483
|
-
buildRouteDisplayItem(parsed) {
|
|
484
|
-
const { route, alreadyImported, parseError, format } = parsed;
|
|
507
|
+
buildRouteDisplayItem(parsed, observer) {
|
|
508
|
+
const { route, alreadyImported, parseError, format, controlFileUri } = parsed;
|
|
485
509
|
const descr = route?.description ?? {};
|
|
486
510
|
const [C, U] = this.getUnitConversionShortcuts();
|
|
487
511
|
const distance = descr.distance === undefined ? undefined : {
|
|
488
512
|
value: C(descr.distance, 'distance', { digits: 1 }),
|
|
489
513
|
unit: U('distance')
|
|
490
514
|
};
|
|
515
|
+
const path = this.getBindings().path;
|
|
516
|
+
const info = path.parse(controlFileUri);
|
|
491
517
|
return {
|
|
492
|
-
id: route
|
|
518
|
+
id: route?.description?.id ?? info?.base,
|
|
493
519
|
distance,
|
|
494
|
-
label: route
|
|
520
|
+
label: route?.title ?? info?.base,
|
|
495
521
|
alreadyImported,
|
|
496
522
|
importable: parseError == null,
|
|
497
523
|
format,
|
|
498
|
-
errorReason: parseError
|
|
524
|
+
errorReason: parseError,
|
|
525
|
+
observer: observer ?? new types_1.Observer()
|
|
499
526
|
};
|
|
500
527
|
}
|
|
501
528
|
getCompanionExts(parsers, primaryExt) {
|
|
@@ -206,6 +206,8 @@ let RoutesPageService = (() => {
|
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
208
|
onImportClicked() {
|
|
209
|
+
if (this.showImportDialog)
|
|
210
|
+
return;
|
|
209
211
|
try {
|
|
210
212
|
this.showImportDialog = true;
|
|
211
213
|
this.getRouteLibraryScanner().prepare();
|
|
@@ -217,7 +219,9 @@ let RoutesPageService = (() => {
|
|
|
217
219
|
}
|
|
218
220
|
importSingleRoute(fileInfo) {
|
|
219
221
|
try {
|
|
220
|
-
|
|
222
|
+
const observer = this.getRouteLibraryScanner().importSingle(fileInfo);
|
|
223
|
+
this.updatePageDisplay();
|
|
224
|
+
return observer;
|
|
221
225
|
}
|
|
222
226
|
catch (err) {
|
|
223
227
|
this.logError(err, 'importSingleRoute');
|
|
@@ -260,11 +264,11 @@ let RoutesPageService = (() => {
|
|
|
260
264
|
}
|
|
261
265
|
onImportClosed() {
|
|
262
266
|
try {
|
|
267
|
+
this.showImportDialog = false;
|
|
263
268
|
if (this.importObserver)
|
|
264
269
|
this.importObserver.stop();
|
|
265
270
|
this.getRouteLibraryScanner().done();
|
|
266
271
|
this.importObserver = undefined;
|
|
267
|
-
this.showImportDialog = false;
|
|
268
272
|
this.getPageObserver().emit('import-closed');
|
|
269
273
|
this.serviceState = this.getRouteList().search();
|
|
270
274
|
this.updatePageDisplay();
|
|
@@ -27,8 +27,8 @@ export class IncyclistXMLParser extends XMLParser {
|
|
|
27
27
|
async loadPoints(context) {
|
|
28
28
|
const { data, fileInfo, route } = context;
|
|
29
29
|
const gpxFile = { ...fileInfo };
|
|
30
|
-
const
|
|
31
|
-
const fileName = data['gpx-file-path'] ??
|
|
30
|
+
const xmlBase = fileInfo.base;
|
|
31
|
+
const fileName = data['gpx-file-path'] ?? xmlBase.replace('.xml', '.gpx');
|
|
32
32
|
if (fileName.startsWith('file') || fileName.startsWith('/') || fileName.startsWith('\\') || fileName.startsWith('.')) {
|
|
33
33
|
gpxFile.type = 'file';
|
|
34
34
|
gpxFile.filename = fileName;
|
|
@@ -38,10 +38,10 @@ export class IncyclistXMLParser extends XMLParser {
|
|
|
38
38
|
gpxFile.url = fileName;
|
|
39
39
|
}
|
|
40
40
|
else if (fileInfo.type === 'url') {
|
|
41
|
-
gpxFile.url = gpxFile.url.replace(
|
|
41
|
+
gpxFile.url = gpxFile.url.replace(xmlBase, fileName);
|
|
42
42
|
}
|
|
43
43
|
else {
|
|
44
|
-
gpxFile.filename = gpxFile.filename.replace(
|
|
44
|
+
gpxFile.filename = gpxFile.filename.replace(xmlBase, fileName);
|
|
45
45
|
}
|
|
46
46
|
try {
|
|
47
47
|
let points;
|
|
@@ -69,7 +69,7 @@ export class BinaryReader {
|
|
|
69
69
|
}
|
|
70
70
|
export const getReferencedFileInfo = (info, referenced, scheme = 'file') => {
|
|
71
71
|
if (info.type !== 'url') {
|
|
72
|
-
return buildFromFile(info, referenced
|
|
72
|
+
return buildFromFile(info, referenced);
|
|
73
73
|
}
|
|
74
74
|
if (referenced.url) {
|
|
75
75
|
return referenced.url;
|
|
@@ -77,6 +77,9 @@ export const getReferencedFileInfo = (info, referenced, scheme = 'file') => {
|
|
|
77
77
|
if (!referenced.file) {
|
|
78
78
|
return;
|
|
79
79
|
}
|
|
80
|
+
if (referenced.file && info.filename?.startsWith('content://')) {
|
|
81
|
+
return `${info.dir}${info.delimiter}${referenced.file}`;
|
|
82
|
+
}
|
|
80
83
|
const targetFileName = referenced.file;
|
|
81
84
|
const regex = /([\\/])/g;
|
|
82
85
|
if (targetFileName.startsWith('http://') || targetFileName.startsWith('https://')) {
|
|
@@ -92,9 +95,9 @@ export const getReferencedFileInfo = (info, referenced, scheme = 'file') => {
|
|
|
92
95
|
return `${scheme}:///${targetFileName}`;
|
|
93
96
|
}
|
|
94
97
|
};
|
|
95
|
-
const buildFromFile = (info, referenced
|
|
98
|
+
const buildFromFile = (info, referenced) => {
|
|
96
99
|
if (referenced.file) {
|
|
97
|
-
const fileName = info.filename?.replace(info.
|
|
100
|
+
const fileName = info.filename?.replace(info.base, referenced.file);
|
|
98
101
|
return `file:///${fileName}`;
|
|
99
102
|
}
|
|
100
103
|
return referenced.url;
|
|
@@ -102,9 +105,8 @@ const buildFromFile = (info, referenced, scheme = 'file') => {
|
|
|
102
105
|
const buildAbsolutePathTarget = (fileName, info, scheme) => {
|
|
103
106
|
const inputUrl = info.url;
|
|
104
107
|
if (inputUrl.startsWith('incyclist:') || inputUrl.startsWith('file:')) {
|
|
105
|
-
const target = {};
|
|
106
108
|
const parts = inputUrl.split('://');
|
|
107
|
-
const targetPath = parts[1].replace(info.
|
|
109
|
+
const targetPath = parts[1].replace(info.base, fileName);
|
|
108
110
|
return `${scheme}://${targetPath}`;
|
|
109
111
|
}
|
|
110
112
|
};
|
|
@@ -92,7 +92,7 @@ let RouteLibraryScannerService = (() => {
|
|
|
92
92
|
this.importProps = undefined;
|
|
93
93
|
}
|
|
94
94
|
getDisplayProps() {
|
|
95
|
-
return this.importProps;
|
|
95
|
+
return { ...this.importProps };
|
|
96
96
|
}
|
|
97
97
|
importSingle(fileInfo) {
|
|
98
98
|
const observer = new Observer();
|
|
@@ -122,8 +122,13 @@ let RouteLibraryScannerService = (() => {
|
|
|
122
122
|
this.logError(err, 'scan', { uri: folderInfo.uri });
|
|
123
123
|
observer.emit('error', err.message);
|
|
124
124
|
});
|
|
125
|
-
observer
|
|
125
|
+
observer
|
|
126
|
+
.on('scan-progress', (progress) => {
|
|
126
127
|
this.importProps.scanProgress = progress;
|
|
128
|
+
})
|
|
129
|
+
.on('scan-complete', () => {
|
|
130
|
+
console.log('# scan-complete');
|
|
131
|
+
this.importProps.phase = 'parsing';
|
|
127
132
|
});
|
|
128
133
|
return observer;
|
|
129
134
|
}
|
|
@@ -140,9 +145,18 @@ let RouteLibraryScannerService = (() => {
|
|
|
140
145
|
this.importProps.parseProgress = { parsed, total };
|
|
141
146
|
});
|
|
142
147
|
observer.on('parse-result', (route) => {
|
|
143
|
-
this.importProps.routes.
|
|
148
|
+
const idx = this.importProps.routes.findIndex(r => r.id === route.controlFileUri);
|
|
149
|
+
if (idx !== -1) {
|
|
150
|
+
const observer = this.importProps.routes[idx].observer;
|
|
151
|
+
const displayProps = this.buildRouteDisplayItem(route, observer);
|
|
152
|
+
this.importProps.routes[idx] = displayProps;
|
|
153
|
+
if (observer) {
|
|
154
|
+
observer.emit('updated', displayProps);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
144
157
|
});
|
|
145
158
|
observer.on('parse-complete', () => {
|
|
159
|
+
console.log('# parse-complete');
|
|
146
160
|
this.importProps.phase = 'selecting';
|
|
147
161
|
});
|
|
148
162
|
return observer;
|
|
@@ -280,7 +294,7 @@ let RouteLibraryScannerService = (() => {
|
|
|
280
294
|
const primaryFiles = files.filter((f) => {
|
|
281
295
|
const name = typeof (f) === 'string' ? f : f.name;
|
|
282
296
|
const ext = this.getExtension(name);
|
|
283
|
-
return ext && parsers.isPrimaryExtension(ext);
|
|
297
|
+
return ext && ext !== 'gpx' && parsers.isPrimaryExtension(ext);
|
|
284
298
|
}).map((f) => {
|
|
285
299
|
if (typeof f === 'string') {
|
|
286
300
|
return {
|
|
@@ -296,6 +310,7 @@ let RouteLibraryScannerService = (() => {
|
|
|
296
310
|
if (!this.isCancelled) {
|
|
297
311
|
const routeAnnouncement = await this.buildDiscoveredRoute(file, files, uri, folderName, parsers);
|
|
298
312
|
discoveredCount.value++;
|
|
313
|
+
console.log('added', routeAnnouncement, this.scanResult.length);
|
|
299
314
|
observer.emit('scan-result', routeAnnouncement);
|
|
300
315
|
this.scanResult.push(routeAnnouncement);
|
|
301
316
|
}
|
|
@@ -332,17 +347,29 @@ let RouteLibraryScannerService = (() => {
|
|
|
332
347
|
const service = this.getRouteList();
|
|
333
348
|
const targets = scannedRoutes.filter(r => !r.scanError);
|
|
334
349
|
const total = targets.length;
|
|
350
|
+
targets.forEach(target => {
|
|
351
|
+
const file = this.buildFileInfo(target.controlFileUri, target.format);
|
|
352
|
+
this.importProps.routes.push({
|
|
353
|
+
format: target.format,
|
|
354
|
+
importable: false,
|
|
355
|
+
label: file.base,
|
|
356
|
+
id: target.controlFileUri,
|
|
357
|
+
alreadyImported: false,
|
|
358
|
+
observer: new Observer()
|
|
359
|
+
});
|
|
360
|
+
});
|
|
361
|
+
observer.emit('parse-start');
|
|
335
362
|
for (let i = 0; i < targets.length; i++) {
|
|
336
363
|
if (this.isCancelled)
|
|
337
364
|
continue;
|
|
338
365
|
const parsed = i + 1;
|
|
339
366
|
const target = targets[i];
|
|
340
367
|
observer.emit('parse-progress', { current: parsed, parsed, total, currentFolder: target.folderName });
|
|
341
|
-
await this._parseTarget(target, service, observer);
|
|
368
|
+
await this._parseTarget(target, service, observer, i);
|
|
342
369
|
}
|
|
343
370
|
observer.emit('parse-complete');
|
|
344
371
|
}
|
|
345
|
-
async _parseTarget(target, service, observer) {
|
|
372
|
+
async _parseTarget(target, service, observer, idx) {
|
|
346
373
|
if (service.existsBySourceUri(target.controlFileUri)) {
|
|
347
374
|
observer.emit('parse-result', {
|
|
348
375
|
alreadyImported: true,
|
|
@@ -462,37 +489,37 @@ let RouteLibraryScannerService = (() => {
|
|
|
462
489
|
}
|
|
463
490
|
}
|
|
464
491
|
buildFileInfo(uri, ext) {
|
|
465
|
-
const
|
|
466
|
-
const dir = uri.slice(0, lastSlash);
|
|
467
|
-
const base = uri.slice(lastSlash + 1);
|
|
468
|
-
const name = base.slice(0, base.length - ext.length - 1);
|
|
492
|
+
const { dir, base, name } = this.getBindings().path.parse(uri);
|
|
469
493
|
return {
|
|
470
|
-
type: '
|
|
494
|
+
type: 'file',
|
|
471
495
|
url: uri,
|
|
472
496
|
filename: uri,
|
|
473
497
|
base,
|
|
474
498
|
name,
|
|
475
499
|
dir,
|
|
476
500
|
ext,
|
|
477
|
-
delimiter: '/'
|
|
501
|
+
delimiter: uri.startsWith('content://') ? '%2F' : '/'
|
|
478
502
|
};
|
|
479
503
|
}
|
|
480
|
-
buildRouteDisplayItem(parsed) {
|
|
481
|
-
const { route, alreadyImported, parseError, format } = parsed;
|
|
504
|
+
buildRouteDisplayItem(parsed, observer) {
|
|
505
|
+
const { route, alreadyImported, parseError, format, controlFileUri } = parsed;
|
|
482
506
|
const descr = route?.description ?? {};
|
|
483
507
|
const [C, U] = this.getUnitConversionShortcuts();
|
|
484
508
|
const distance = descr.distance === undefined ? undefined : {
|
|
485
509
|
value: C(descr.distance, 'distance', { digits: 1 }),
|
|
486
510
|
unit: U('distance')
|
|
487
511
|
};
|
|
512
|
+
const path = this.getBindings().path;
|
|
513
|
+
const info = path.parse(controlFileUri);
|
|
488
514
|
return {
|
|
489
|
-
id: route
|
|
515
|
+
id: route?.description?.id ?? info?.base,
|
|
490
516
|
distance,
|
|
491
|
-
label: route
|
|
517
|
+
label: route?.title ?? info?.base,
|
|
492
518
|
alreadyImported,
|
|
493
519
|
importable: parseError == null,
|
|
494
520
|
format,
|
|
495
|
-
errorReason: parseError
|
|
521
|
+
errorReason: parseError,
|
|
522
|
+
observer: observer ?? new Observer()
|
|
496
523
|
};
|
|
497
524
|
}
|
|
498
525
|
getCompanionExts(parsers, primaryExt) {
|
|
@@ -203,6 +203,8 @@ let RoutesPageService = (() => {
|
|
|
203
203
|
}
|
|
204
204
|
}
|
|
205
205
|
onImportClicked() {
|
|
206
|
+
if (this.showImportDialog)
|
|
207
|
+
return;
|
|
206
208
|
try {
|
|
207
209
|
this.showImportDialog = true;
|
|
208
210
|
this.getRouteLibraryScanner().prepare();
|
|
@@ -214,7 +216,9 @@ let RoutesPageService = (() => {
|
|
|
214
216
|
}
|
|
215
217
|
importSingleRoute(fileInfo) {
|
|
216
218
|
try {
|
|
217
|
-
|
|
219
|
+
const observer = this.getRouteLibraryScanner().importSingle(fileInfo);
|
|
220
|
+
this.updatePageDisplay();
|
|
221
|
+
return observer;
|
|
218
222
|
}
|
|
219
223
|
catch (err) {
|
|
220
224
|
this.logError(err, 'importSingleRoute');
|
|
@@ -257,11 +261,11 @@ let RoutesPageService = (() => {
|
|
|
257
261
|
}
|
|
258
262
|
onImportClosed() {
|
|
259
263
|
try {
|
|
264
|
+
this.showImportDialog = false;
|
|
260
265
|
if (this.importObserver)
|
|
261
266
|
this.importObserver.stop();
|
|
262
267
|
this.getRouteLibraryScanner().done();
|
|
263
268
|
this.importObserver = undefined;
|
|
264
|
-
this.showImportDialog = false;
|
|
265
269
|
this.getPageObserver().emit('import-closed');
|
|
266
270
|
this.serviceState = this.getRouteList().search();
|
|
267
271
|
this.updatePageDisplay();
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ReadDirResult } from "../../api";
|
|
2
2
|
import { FormattedNumber } from "../../i18n";
|
|
3
|
+
import { IObserver } from "../../types";
|
|
3
4
|
import { Route } from "../base/model/route";
|
|
4
5
|
export interface FolderInfo {
|
|
5
6
|
uri: string;
|
|
@@ -21,6 +22,7 @@ export interface ParsedRoute {
|
|
|
21
22
|
alreadyImported: boolean;
|
|
22
23
|
parseError?: string;
|
|
23
24
|
format: RouteFormat;
|
|
25
|
+
observer: IObserver;
|
|
24
26
|
}
|
|
25
27
|
export interface RouteDisplayItem {
|
|
26
28
|
id: string;
|
|
@@ -30,6 +32,7 @@ export interface RouteDisplayItem {
|
|
|
30
32
|
alreadyImported: boolean;
|
|
31
33
|
importable: boolean;
|
|
32
34
|
errorReason?: string;
|
|
35
|
+
observer: IObserver;
|
|
33
36
|
}
|
|
34
37
|
export interface ImportDisplayProps {
|
|
35
38
|
phase: 'landing' | 'scanning' | 'parsing' | 'selecting' | 'ingesting' | 'complete' | 'result' | 'error';
|