195 lines
4.9 KiB
JavaScript
Raw Normal View History

2025-03-07 13:14:32 +01:00
export class PathSelector {
2025-04-02 10:15:32 +02:00
constructor(uiService, menuLoop, fsService) {
2025-03-07 13:14:32 +01:00
this.ui = uiService;
2025-04-02 10:15:32 +02:00
this.loop = menuLoop;
2025-03-07 13:14:32 +01:00
this.fs = fsService;
2025-02-20 10:04:58 +01:00
2025-03-07 13:14:32 +01:00
this.pathMustExist = true;
2025-04-02 10:15:32 +02:00
this.loop.initialize(this.showPathSelector);
2025-02-20 10:04:58 +01:00
}
2025-02-17 15:13:47 +01:00
2025-03-31 14:26:57 +02:00
show = async (startingPath, pathMustExist) => {
this.startingPath = startingPath;
2025-03-07 13:14:32 +01:00
this.pathMustExist = pathMustExist;
this.roots = this.fs.getAvailableRoots();
this.currentPath = this.splitPath(startingPath);
if (!this.hasValidRoot(this.currentPath)) {
2025-04-02 10:29:03 +02:00
this.currentPath = [this.roots[0]];
2025-02-19 14:56:22 +01:00
}
2025-04-02 10:15:32 +02:00
await this.loop.showLoop();
2025-03-31 14:26:57 +02:00
return this.resultingPath;
2025-03-07 13:14:32 +01:00
};
2025-04-02 10:15:32 +02:00
showPathSelector = async () => {
this.showCurrent();
await this.ui.askMultipleChoice("Select an option:", [
{
label: "Enter path",
action: this.enterPath,
},
{
label: "Go up one",
action: this.upOne,
},
{
label: "Go down one",
action: this.downOne,
},
{
label: "Create new folder here",
action: this.createSubDir,
},
{
label: "Select this path",
action: this.selectThisPath,
},
{
label: "Cancel",
action: this.cancel,
},
]);
};
2025-03-07 13:14:32 +01:00
splitPath = (str) => {
2025-04-02 14:45:23 +02:00
var result = this.dropEmptyParts(str.replaceAll("\\", "/").split("/"));
if (str.startsWith("/") && this.roots.includes("/")) {
2025-04-07 16:01:49 +02:00
result = ["/", ...result];
}
return result;
2025-03-07 13:14:32 +01:00
};
dropEmptyParts = (parts) => {
2025-04-07 16:01:49 +02:00
return parts.filter((part) => part.length > 0);
2025-03-07 13:14:32 +01:00
};
combine = (parts) => {
const toJoin = this.dropEmptyParts(parts);
if (toJoin.length == 1) return toJoin[0];
2025-04-02 14:45:23 +02:00
var result = this.fs.pathJoin(toJoin);
if (result.startsWith("//")) {
result = result.substring(1);
}
2025-04-02 10:15:32 +02:00
return result;
2025-03-07 13:14:32 +01:00
};
combineWith = (parts, extra) => {
const toJoin = this.dropEmptyParts(parts);
2025-04-02 10:15:32 +02:00
if (toJoin.length == 1) return this.fs.pathJoin([toJoin[0], extra]);
return this.fs.pathJoin([...toJoin, extra]);
2025-03-07 13:14:32 +01:00
};
showCurrent = () => {
const len = this.currentPath.length;
this.ui.showInfoMessage(
`Current path: [${len}]\n` + this.combine(this.currentPath),
);
2025-02-17 15:13:47 +01:00
2025-03-07 13:14:32 +01:00
if (len < 2) {
this.ui.showInfoMessage(
"Warning - Known issue:\n" +
"Path selection does not work in root paths on some platforms.\n" +
'Use "Enter path" or "Create new folder" to navigate and create folders\n' +
"if this is the case for you.",
);
2025-02-17 15:13:47 +01:00
}
2025-03-07 13:14:32 +01:00
};
hasValidRoot = (checkPath) => {
if (checkPath.length < 1) return false;
var result = false;
this.roots.forEach(function (root) {
if (root.toLowerCase() == checkPath[0].toLowerCase()) {
result = true;
}
});
return result;
};
2025-02-20 10:04:58 +01:00
2025-03-07 13:14:32 +01:00
updateCurrentIfValidFull = (newFullPath) => {
if (this.pathMustExist && !this.fs.isDir(newFullPath)) {
2025-04-02 10:15:32 +02:00
this.ui.showErrorMessage("The path does not exist.");
return;
2025-02-20 10:04:58 +01:00
}
2025-03-07 13:14:32 +01:00
this.updateCurrentIfValidParts(this.splitPath(newFullPath));
2025-04-01 14:33:44 +02:00
};
2025-02-17 15:13:47 +01:00
2025-03-07 13:14:32 +01:00
updateCurrentIfValidParts = (newParts) => {
if (!this.hasValidRoot(newParts)) {
2025-04-02 10:15:32 +02:00
this.ui.showErrorMessage("The path has no valid root.");
return;
2025-03-07 13:14:32 +01:00
}
this.currentPath = newParts;
2025-04-01 14:33:44 +02:00
};
2025-02-17 15:13:47 +01:00
2025-03-07 13:14:32 +01:00
enterPath = async () => {
const newPath = await this.ui.askPrompt("Enter Path:");
this.updateCurrentIfValidFull(newPath);
};
upOne = () => {
const newParts = this.currentPath.slice(0, this.currentPath.length - 1);
this.updateCurrentIfValidParts(newParts);
};
isSubDir = (entry) => {
const newPath = this.combineWith(this.currentPath, entry);
return this.fs.isDir(newPath);
};
getSubDirOptions = () => {
const fullPath = this.combine(this.currentPath);
try {
const entries = this.fs.readDir(fullPath);
return entries.filter((entry) => this.isSubDir(entry));
2025-04-09 10:27:00 +02:00
} catch {
return [];
}
2025-03-07 13:14:32 +01:00
};
2025-02-17 15:13:47 +01:00
2025-03-07 13:14:32 +01:00
downOne = async () => {
const options = this.getSubDirOptions();
if (options.length == 0) {
2025-04-02 10:15:32 +02:00
this.ui.showInfoMessage("There are no subdirectories here.");
return;
2025-02-17 15:13:47 +01:00
}
2025-03-07 13:14:32 +01:00
var selected = "";
2025-03-31 13:26:53 +02:00
var uiOptions = [];
2025-04-02 10:15:32 +02:00
options.forEach(function (option) {
2025-03-31 13:26:53 +02:00
uiOptions.push({
label: option,
action: () => {
selected = option;
2025-03-07 13:14:32 +01:00
},
2025-04-01 14:33:44 +02:00
});
});
2025-03-07 13:14:32 +01:00
2025-03-31 13:26:53 +02:00
await this.ui.askMultipleChoice("Select an subdir", uiOptions);
2025-03-07 13:14:32 +01:00
2025-03-31 13:26:53 +02:00
if (selected.length < 1) return;
this.updateCurrentIfValidParts([...this.currentPath, selected]);
};
2025-02-17 15:13:47 +01:00
2025-03-31 13:26:53 +02:00
createSubDir = async () => {
const name = await this.ui.askPrompt("Enter name:");
2025-03-07 13:14:32 +01:00
if (name.length < 1) return;
2025-04-02 10:15:32 +02:00
const newPath = [...this.currentPath, name];
if (this.pathMustExist) {
this.fs.makeDir(this.combine(newPath));
}
this.updateCurrentIfValidParts(newPath);
2025-03-07 13:14:32 +01:00
};
2025-03-31 14:26:57 +02:00
selectThisPath = async () => {
this.resultingPath = this.combine(this.currentPath);
2025-04-02 10:15:32 +02:00
this.loop.stopLoop();
2025-04-01 14:33:44 +02:00
};
2025-03-31 14:26:57 +02:00
cancel = async () => {
this.resultingPath = this.startingPath;
2025-04-02 10:15:32 +02:00
this.loop.stopLoop();
2025-03-31 14:26:57 +02:00
};
2025-02-17 15:13:47 +01:00
}