Folder picker: create a new folder (new automation, new chat)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
538aac9122
commit
7298102e93
5 files changed
+33
No files matched your search
@@ -3,6 +3,13 @@
|
|||||||
All notable changes to CodeCraft. Versions follow [Semantic Versioning](https://semver.org/);
|
All notable changes to CodeCraft. Versions follow [Semantic Versioning](https://semver.org/);
|
||||||
until 1.0, minor versions may contain breaking changes.
|
until 1.0, minor versions may contain breaking changes.
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- **New folder in the folder picker:** creating an automation or a chat, *New folder* creates a
|
||||||
|
subfolder of the shown folder and selects it.
|
||||||
|
|
||||||
## [v202611-00013] – 2026-11-10
|
## [v202611-00013] – 2026-11-10
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Icon } from "./Icon";
|
import { Icon } from "./Icon";
|
||||||
import { useEffect, useMemo, useRef, useState, type ReactNode } from "react";
|
import { useEffect, useMemo, useRef, useState, type ReactNode } from "react";
|
||||||
import { post, uploadFile } from "../api";
|
import { post, uploadFile } from "../api";
|
||||||
|
import { promptDialog, toast } from "../dialogs";
|
||||||
import { useAgents, useFetch } from "../hooks";
|
import { useAgents, useFetch } from "../hooks";
|
||||||
import { useT, type Key } from "../i18n";
|
import { useT, type Key } from "../i18n";
|
||||||
import type { ImageData } from "../types";
|
import type { ImageData } from "../types";
|
||||||
@@ -602,6 +603,20 @@ export function FolderPicker({ path, onPick }: { path: string; onPick: (p: strin
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [listing?.path]);
|
}, [listing?.path]);
|
||||||
const rel = listing ? listing.path.slice(listing.workspace.length) || "/" : "";
|
const rel = listing ? listing.path.slice(listing.workspace.length) || "/" : "";
|
||||||
|
/** Create a subfolder of the shown folder and select it. */
|
||||||
|
const newFolder = async () => {
|
||||||
|
if (!listing) return;
|
||||||
|
const name = (await promptDialog({ title: t("files.newFolder"), message: t("files.newFolderName") }))?.trim();
|
||||||
|
if (!name) return;
|
||||||
|
if (name.includes("/") || name === "." || name === "..") return toast(t("new.invalidFolderName"));
|
||||||
|
const target = `${listing.path.replace(/\/$/, "")}/${name}`;
|
||||||
|
try {
|
||||||
|
await post("/files/create", { path: target, dir: true });
|
||||||
|
setBrowse(target);
|
||||||
|
} catch (e: any) {
|
||||||
|
toast(e.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<div className="wiz-picker">
|
<div className="wiz-picker">
|
||||||
{roots.length > 1 && (
|
{roots.length > 1 && (
|
||||||
@@ -622,6 +637,11 @@ export function FolderPicker({ path, onPick }: { path: string; onPick: (p: strin
|
|||||||
<Icon name="arrow-up" /> {t("new.up")}
|
<Icon name="arrow-up" /> {t("new.up")}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
{listing && (
|
||||||
|
<button className="small" onClick={() => void newFolder()}>
|
||||||
|
<Icon name="plus" /> {t("files.newFolder")}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="dir-list">
|
<div className="dir-list">
|
||||||
{listing?.dirs.length === 0 && <div className="empty" style={{ padding: 16 }}>{t("new.noSubdirs")}</div>}
|
{listing?.dirs.length === 0 && <div className="empty" style={{ padding: 16 }}>{t("new.noSubdirs")}</div>}
|
||||||
|
|||||||
@@ -554,6 +554,7 @@ export const de: Messages = {
|
|||||||
"jobs.tplMode": "Modus",
|
"jobs.tplMode": "Modus",
|
||||||
"new.title": "Neue Session",
|
"new.title": "Neue Session",
|
||||||
"new.directory": "Projektverzeichnis",
|
"new.directory": "Projektverzeichnis",
|
||||||
|
"new.invalidFolderName": "Ordnernamen dürfen kein „/“ enthalten.",
|
||||||
"new.up": "Hoch",
|
"new.up": "Hoch",
|
||||||
"new.noSubdirs": "Keine Unterverzeichnisse",
|
"new.noSubdirs": "Keine Unterverzeichnisse",
|
||||||
"new.model": "Modell",
|
"new.model": "Modell",
|
||||||
|
|||||||
@@ -553,6 +553,7 @@ export const en = {
|
|||||||
"jobs.tplMode": "Mode",
|
"jobs.tplMode": "Mode",
|
||||||
"new.title": "New session",
|
"new.title": "New session",
|
||||||
"new.directory": "Project directory",
|
"new.directory": "Project directory",
|
||||||
|
"new.invalidFolderName": "Folder names cannot contain “/”.",
|
||||||
"new.up": "Up",
|
"new.up": "Up",
|
||||||
"new.noSubdirs": "No subdirectories",
|
"new.noSubdirs": "No subdirectories",
|
||||||
"new.model": "Model",
|
"new.model": "Model",
|
||||||
|
|||||||
@@ -3,6 +3,10 @@
|
|||||||
* under "unreleased"; scripts/release.sh renames the key to the release version.
|
* under "unreleased"; scripts/release.sh renames the key to the release version.
|
||||||
*/
|
*/
|
||||||
export const WHATS_NEW: Record<string, { en: string[]; de: string[] }> = {
|
export const WHATS_NEW: Record<string, { en: string[]; de: string[] }> = {
|
||||||
|
unreleased: {
|
||||||
|
en: ["Folder picker (new automation, new chat): create a new folder right there"],
|
||||||
|
de: ["Ordnerauswahl (neue Automatisierung, neuer Chat): direkt einen neuen Ordner anlegen"],
|
||||||
|
},
|
||||||
"202611-00013": {
|
"202611-00013": {
|
||||||
en: [
|
en: [
|
||||||
"New automation editor: instructions, a graphical schedule and an assistant chat that writes the instructions with you",
|
"New automation editor: instructions, a graphical schedule and an assistant chat that writes the instructions with you",
|
||||||
|
|||||||
Reference in new issue
Block a user