Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 13 additions & 11 deletions webapp/e2e/studio-nocturne.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5009,7 +5009,9 @@ test("files tracks into folders from the menu and by dragging", async ({
await page.goto("/folders");
await expect(page.getByRole("heading", { name: "Folders" })).toBeVisible();
const cards = page.getByRole("list", { name: "Folders" });
await expect(cards.getByRole("link", { name: /Unfiled/ })).toContainText("3 tracks");
await expect(cards.getByRole("link", { name: /To sort/ })).toContainText("3 tracks");
// WaveFlow's list, not a folder of the owner's, and it says so.
await expect(cards.getByRole("link", { name: /To sort/ })).toContainText("Automatic");

// A folder, and a second one refused for a name already taken.
await page.getByRole("button", { name: "New folder" }).click();
Expand All @@ -5025,8 +5027,8 @@ test("files tracks into folders from the menu and by dragging", async ({
await page.getByRole("button", { name: "Cancel" }).click();

// From the menu: the unfiled tracks, the first one filed into Rock.
await cards.getByRole("link", { name: /Unfiled/ }).click();
await expect(page.getByRole("heading", { name: "Unfiled" })).toBeVisible();
await cards.getByRole("link", { name: /To sort/ }).click();
await expect(page.getByRole("heading", { name: "To sort" })).toBeVisible();
const rows = page.locator(".songs tbody tr");
await expect(rows).toHaveCount(3);
await rows.first().locator("button.song-title").focus();
Expand All @@ -5048,7 +5050,7 @@ test("files tracks into folders from the menu and by dragging", async ({
// there, where it would read as a folder inside "Unfiled".
await expect(page.getByRole("list", { name: "Folders" })).toHaveCount(0);
await expect(
page.getByText("To file one, open its menu", { exact: false }),
page.getByText("To file a track, open its menu", { exact: false }),
).toBeVisible();

// Inside the folder: a second track, a sub-folder, and a drag onto it. A
Expand Down Expand Up @@ -5081,9 +5083,9 @@ test("files tracks into folders from the menu and by dragging", async ({
await page.getByRole("button", { name: "Delete" }).click();
await expect(page.getByRole("heading", { name: "Folders" })).toBeVisible();
await expect(page.getByRole("status")).toHaveText(
"Folder deleted: 2 tracks are unfiled.",
"Folder deleted: 2 tracks are back in To sort.",
);
await expect(cards.getByRole("link", { name: /Unfiled/ })).toContainText("3 tracks");
await expect(cards.getByRole("link", { name: /To sort/ })).toContainText("3 tracks");
await expectNoWcagViolations(page);
});

Expand All @@ -5100,7 +5102,7 @@ test("shows a listener the filed tree with nothing to change", async ({ page })
await expect(page.getByRole("button", { name })).toHaveCount(0);
}
// A reader is told what Unfiled is, not how to file, and rows do not drag.
await expect(page.getByText("Tracks that are in no folder yet.", { exact: true })).toBeVisible();
await expect(page.getByText("WaveFlow keeps this list itself", { exact: false })).toBeVisible();
await expect(page.locator(".songs tbody tr").first()).not.toHaveAttribute("draggable", "true");
await page.locator(".songs tbody tr button.song-title").first().focus();
await page.keyboard.press("Shift+F10");
Expand Down Expand Up @@ -5158,7 +5160,7 @@ test("keeps a received track when filing it fails, and says so", async ({
mimeType: "audio/flac",
buffer: Buffer.from(Array.from({ length: 20 }, (_, i) => i)),
});
await expect(page.getByText("Added to the library, but not filed")).toBeVisible();
await expect(page.getByText("Added to the library, in To sort")).toBeVisible();
expect(uploadCommits).toEqual(["upload-1"]);
});

Expand Down Expand Up @@ -5187,7 +5189,7 @@ test("waits for the folder before taking files, and says when it is gone", async
}
await expect(page.getByLabel("Choose audio files")).toBeEnabled();
await expect(page.getByRole("status")).toHaveText(
"The folder this upload was opened for cannot be found: received files will stay unfiled.",
"The folder this upload was opened for cannot be found: received files will go to To sort.",
);
});

Expand Down Expand Up @@ -5324,8 +5326,8 @@ test("closes a folder's form when another folder is opened", async ({ page }) =>
await page.goto("/folders");
await page.getByRole("button", { name: "New folder" }).click();
await expect(page.getByLabel("Folder name")).toBeVisible();
await page.getByRole("list", { name: "Folders" }).getByRole("link", { name: /Unfiled/ }).click();
await expect(page.getByRole("heading", { name: "Unfiled" })).toBeVisible();
await page.getByRole("list", { name: "Folders" }).getByRole("link", { name: /To sort/ }).click();
await expect(page.getByRole("heading", { name: "To sort" })).toBeVisible();
await expect(page.getByLabel("Folder name")).toHaveCount(0);
expect(state.writes).toEqual([]);
});
10 changes: 9 additions & 1 deletion webapp/src/components/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,17 @@ export type IconName =
| "info"
| "download"
| "folder"
| "back";
| "back"
| "inbox";

const paths: Record<IconName, ReactNode> = {
// A tray: what has arrived and is waiting to be put away.
inbox: (
<>
<path d="M4 13h4l1.5 2.5h5L16 13h4" />
<path d="M6 5h12l3 8v5a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-5z" />
</>
),
// An arrow pointing left: back to where the visitor came from.
back: (
<>
Expand Down
11 changes: 9 additions & 2 deletions webapp/src/pages/folders-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -375,8 +375,15 @@ export function FoldersPage({ folder }: { folder: string }) {
}
{...dropProps(target)}
>
<Icon name="folder" size={20} />
<span>{label}</span>
{/* To sort is WaveFlow's list, not one of the owner's folders: a tray
rather than a folder, and a badge that says it keeps itself. */}
<Icon name={target ? "folder" : "inbox"} size={20} />
<span>
{label}
{target ? null : (
<small className="folder-badge">{t("filed.automatic")}</small>
)}
</span>
<small className="muted">{t("common.tracks", { count })}</small>
</Link>
</li>
Expand Down
35 changes: 19 additions & 16 deletions webapp/src/state/i18n.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,8 @@ const en = {
"folders.where": "Folder path",
"folders.subfolders": "Folders",
"folders.noLibrary": "No library is available to this account.",
"filed.unfiled": "Unfiled",
"filed.unfiled": "To sort",
"filed.automatic": "Automatic",
"filed.topLevel": "Top level",
"filed.here": "Here now",
"filed.destinations": "Folders to choose from",
Expand All @@ -467,12 +468,12 @@ const en = {
"filed.move": "Move…",
"filed.delete": "Delete",
"filed.confirmDelete":
"Delete “{name}” and its sub-folders? Their tracks become unfiled; no file is touched.",
"Delete “{name}” and its sub-folders? Their tracks go back to To sort; no file is touched.",
"filed.created": "“{name}” created.",
"filed.renamed": "Renamed to “{name}”.",
"filed.deleted": {
one: "Folder deleted: {count} track is unfiled.",
other: "Folder deleted: {count} tracks are unfiled.",
one: "Folder deleted: {count} track is back in To sort.",
other: "Folder deleted: {count} tracks are back in To sort.",
},
"filed.filed": {
one: "{count} track filed in {folder}.",
Expand All @@ -488,13 +489,14 @@ const en = {
"filed.allFiled": "Every track is filed.",
"filed.uploadHere": "Upload here",
"filed.unfiledNote":
"Tracks that are in no folder yet. To file one, open its menu and choose “Move to folder…”.",
"filed.unfiledNoteReader": "Tracks that are in no folder yet.",
"Every track that is in no folder yet. WaveFlow keeps this list itself: a track leaves it as soon as it is filed, and it cannot be renamed or deleted. To file a track, open its menu and choose “Move to folder…”.",
"filed.unfiledNoteReader":
"Every track that is in no folder yet. WaveFlow keeps this list itself: a track leaves it as soon as it is filed.",
"trackMenu.move": "Move to folder…",
"upload.into": "Received files go into the folder {folder}.",
"upload.doneUnfiled": "Added to the library, but not filed",
"upload.doneUnfiled": "Added to the library, in To sort",
"upload.folderMissing":
"The folder this upload was opened for cannot be found: received files will stay unfiled.",
"The folder this upload was opened for cannot be found: received files will go to To sort.",
"upload.folderUnchecked":
"The folder this upload was opened for could not be checked, so no file is taken yet.",
"upload.checkAgain": "Check again",
Expand Down Expand Up @@ -1134,7 +1136,8 @@ const fr: Record<TranslationKey, TranslationValue> = {
"folders.where": "Chemin du dossier",
"folders.subfolders": "Dossiers",
"folders.noLibrary": "Aucune bibliothèque n’est accessible à ce compte.",
"filed.unfiled": "Non classés",
"filed.unfiled": "À ranger",
"filed.automatic": "Automatique",
"filed.topLevel": "Premier niveau",
"filed.here": "Ici actuellement",
"filed.destinations": "Dossiers au choix",
Expand All @@ -1154,12 +1157,12 @@ const fr: Record<TranslationKey, TranslationValue> = {
"filed.move": "Déplacer…",
"filed.delete": "Supprimer",
"filed.confirmDelete":
"Supprimer « {name} » et ses sous-dossiers ? Leurs pistes redeviennent non classées ; aucun fichier n’est touché.",
"Supprimer « {name} » et ses sous-dossiers ? Leurs pistes reviennent dans À ranger ; aucun fichier n’est touché.",
"filed.created": "« {name} » créé.",
"filed.renamed": "Renommé en « {name} ».",
"filed.deleted": {
one: "Dossier supprimé : {count} piste n’est plus classée.",
other: "Dossier supprimé : {count} pistes ne sont plus classées.",
one: "Dossier supprimé : {count} piste revient dans À ranger.",
other: "Dossier supprimé : {count} pistes reviennent dans À ranger.",
},
"filed.filed": {
one: "{count} piste classée dans {folder}.",
Expand All @@ -1175,14 +1178,14 @@ const fr: Record<TranslationKey, TranslationValue> = {
"filed.allFiled": "Toutes les pistes sont classées.",
"filed.uploadHere": "Envoyer ici",
"filed.unfiledNote":
"Les pistes qui ne sont encore dans aucun dossier. Pour en classer une, ouvrez son menu et choisissez « Déplacer vers un dossier… ».",
"Toutes les pistes qui ne sont encore dans aucun dossier. WaveFlow tient cette liste lui-même : une piste en sort dès qu’elle est rangée, et elle ne peut être ni renommée ni supprimée. Pour ranger une piste, ouvrez son menu et choisissez « Déplacer vers un dossier… ».",
"filed.unfiledNoteReader":
"Les pistes qui ne sont encore dans aucun dossier.",
"Toutes les pistes qui ne sont encore dans aucun dossier. WaveFlow tient cette liste lui-même : une piste en sort dès qu’elle est rangée.",
"trackMenu.move": "Déplacer vers un dossier…",
"upload.into": "Les fichiers reçus vont dans le dossier {folder}.",
"upload.doneUnfiled": "Ajouté à la bibliothèque, mais pas classé",
"upload.doneUnfiled": "Ajouté à la bibliothèque, dans À ranger",
"upload.folderMissing":
"Le dossier pour lequel cet envoi a été ouvert est introuvable : les fichiers reçus resteront non classés.",
"Le dossier pour lequel cet envoi a été ouvert est introuvable : les fichiers reçus iront dans À ranger.",
"upload.folderUnchecked":
"Le dossier pour lequel cet envoi a été ouvert n’a pas pu être vérifié : aucun fichier n’est pris pour l’instant.",
"upload.checkAgain": "Vérifier à nouveau",
Expand Down
11 changes: 11 additions & 0 deletions webapp/src/styles/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -3055,3 +3055,14 @@ button.danger {
background: var(--panel-soft);
color: var(--text);
}

/* A list WaveFlow keeps itself, not a folder anyone made. */
.folder-badge {
margin-inline-start: var(--space-2);
padding: 0.1rem var(--space-2);
border: 1px solid var(--line-strong);
border-radius: 999px;
color: var(--muted);
font-size: var(--text-xs);
vertical-align: middle;
}
Loading