This commit is contained in:
97
www/map-import.js
Normal file
97
www/map-import.js
Normal file
@@ -0,0 +1,97 @@
|
||||
(() => {
|
||||
const t = (key, vars) => window.I18n?.t(key, vars) ?? key;
|
||||
|
||||
function fileStem(name) {
|
||||
const base = String(name).replace(/^.*[/\\]/, "");
|
||||
const dot = base.lastIndexOf(".");
|
||||
return dot >= 0 ? base.slice(0, dot) : base;
|
||||
}
|
||||
|
||||
function isYamlFile(file) {
|
||||
return /\.ya?ml$/i.test(file.name);
|
||||
}
|
||||
|
||||
function isMapImageFile(file) {
|
||||
return /\.(png|pgm)$/i.test(file.name);
|
||||
}
|
||||
|
||||
async function matchRosMapFiles(fileList) {
|
||||
const files = Array.from(fileList || []);
|
||||
const yamlFile = files.find(isYamlFile);
|
||||
if (!yamlFile) {
|
||||
throw new Error(t("maps.importNeedYaml"));
|
||||
}
|
||||
|
||||
let imageFile = files.find((f) => f !== yamlFile && isMapImageFile(f));
|
||||
try {
|
||||
const yamlText = await yamlFile.text();
|
||||
const imageRef = yamlText.match(/^image:\s*(\S+)/m)?.[1];
|
||||
if (imageRef) {
|
||||
const refStem = fileStem(imageRef);
|
||||
const matched = files.find(
|
||||
(f) => f !== yamlFile && isMapImageFile(f) && fileStem(f.name) === refStem,
|
||||
);
|
||||
if (matched) imageFile = matched;
|
||||
}
|
||||
} catch {
|
||||
/* best-effort stem match */
|
||||
}
|
||||
|
||||
if (!imageFile) {
|
||||
throw new Error(t("maps.importNeedImage"));
|
||||
}
|
||||
|
||||
return { yamlFile, imageFile };
|
||||
}
|
||||
|
||||
function buildFormData(yamlFile, imageFile, extras = {}) {
|
||||
const form = new FormData();
|
||||
form.append("yaml", yamlFile, yamlFile.name);
|
||||
form.append("image", imageFile, imageFile.name);
|
||||
Object.entries(extras).forEach(([key, value]) => {
|
||||
if (value != null && value !== "") form.append(key, value);
|
||||
});
|
||||
return form;
|
||||
}
|
||||
|
||||
async function apiImport(path, form) {
|
||||
const res = await fetch(path, { method: "POST", credentials: "include", body: form });
|
||||
if (!res.ok) {
|
||||
let msg = res.statusText;
|
||||
try {
|
||||
const err = await res.json();
|
||||
if (err.error) msg = err.error;
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
throw new Error(msg);
|
||||
}
|
||||
return res.json();
|
||||
}
|
||||
|
||||
async function importNewMap(fileList, extras = {}) {
|
||||
const { yamlFile, imageFile } = await matchRosMapFiles(fileList);
|
||||
const form = buildFormData(yamlFile, imageFile, {
|
||||
name: extras.name || fileStem(yamlFile.name),
|
||||
site_id: extras.site_id || "",
|
||||
created_by: extras.created_by || "",
|
||||
description: extras.description || "",
|
||||
});
|
||||
return apiImport("/api/maps/import", form);
|
||||
}
|
||||
|
||||
async function importOverwriteMap(mapId, fileList) {
|
||||
const { yamlFile, imageFile } = await matchRosMapFiles(fileList);
|
||||
const form = buildFormData(yamlFile, imageFile);
|
||||
return apiImport(`/api/maps/${encodeURIComponent(mapId)}/import`, form);
|
||||
}
|
||||
|
||||
window.MapImport = {
|
||||
fileStem,
|
||||
isYamlFile,
|
||||
isMapImageFile,
|
||||
matchRosMapFiles,
|
||||
importNewMap,
|
||||
importOverwriteMap,
|
||||
};
|
||||
})();
|
||||
Reference in New Issue
Block a user