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
1 change: 1 addition & 0 deletions frontend/src/components/common/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export function FolderTypeIcon({
style={{
transform: isOpen ? "rotate(90deg)" : "",
transition: "transform 0.15s ease-in-out",
flexShrink: 0,
}}
{...props}
/>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/frontpage/statsCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ export function CardHeader({
paddingLeft: reverse ? 1 : 4,
paddingRight: reverse ? 4 : 1,
display: "flex",
alignItems: "flex-start",
alignItems: "flex-end",
justifyContent: "space-between",
zIndex: 1,
flexDirection: reverse ? "row-reverse" : "row",
Expand Down
164 changes: 164 additions & 0 deletions frontend/src/components/inbox/cards/inboxCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import { useMemo } from "react";
import { Box, Card, CardContent, Tooltip, Typography } from "@mui/material";

import { useConfig } from "@/api/config";
import { InboxTypeIcon } from "@/components/common/icons";
import { CardHeader } from "@/components/frontpage/statsCard";
import { FolderActionDesktopBar } from "@/components/inbox/actions";
import {
FolderComponent,
GridWrapper,
SelectedStats,
} from "@/components/inbox/fileTree";
import { Folder } from "@/pythonTypes";

export function InboxCard({ folder }: { folder: Folder }) {
const config = useConfig();

// configuration for this inbox folder
const folderConfig = useMemo<(typeof config)["gui"]["inbox"]["folders"][0]>(() => {
const fc = Object.entries(config.gui.inbox.folders).find(
([_k, v]) => v.path === folder.full_path
);

return fc
? fc[1]
: {
name: "Inbox",
autotag: false,
path: folder.full_path,
};
}, [config, folder.full_path]);

const innerFolders = useMemo(() => {
// Filter out folders that are not albums or files
return folder.children.filter((f) => f.type === "directory");
}, [folder.children]);

const threshold = folderConfig.auto_threshold ?? config.match.strong_rec_thresh;

let tooltip: string;
switch (folderConfig.autotag) {
case "auto":
tooltip =
"Automatic tagging and import enabled. " +
(1 - threshold) * 100 +
"% threshold.";
break;
case "preview":
tooltip = "Automatic tagging enabled, but no import.";
break;
case "bootleg":
tooltip = "Import as-is, and split albums by meta-data.";
break;
default:
tooltip = "No automatic tagging or import enabled.";
break;
}

return (
<Card sx={{ width: "100%", padding: 2 }}>
<CardHeader
key={folder.full_path}
icon={
<Tooltip title={tooltip}>
<InboxTypeIcon
size={24}
type={folderConfig.autotag || undefined}
/>
</Tooltip>
}
dividerPos="70%"
color="secondary.main"
>
<Box
sx={{
display: "flex",
alignItems: "flex-end",
width: "100%",
justifyContent: "space-between",
position: "relative",
paddingBottom: 2.5,
paddingLeft: 1,
}}
>
{/* file path */}
<Box
sx={{
display: "flex",
flexWrap: "wrap",
flexDirection: "row",
alignItems: "flex-end",
width: "100%",

columnGap: 0.5,
rowGap: 0.1,
}}
>
{folderConfig.path
.split("/")
.filter(Boolean)
.map((segment, idx, arr) => (
<Typography
variant="body2"
key={idx}
component="span"
sx={{
display: "inline-flex",
whiteSpace: "nowrap",
}}
>
{`/ ${segment}${idx === arr.length - 1 && folderConfig.path.endsWith("/") ? " /" : ""}`}
</Typography>
))}
</Box>

{/* inbox name */}
<Typography
variant="body1"
sx={{
fontWeight: "bold",
flexShrink: 0,
m: 0,
p: 0,
}}
>
{folderConfig.name}
</Typography>
</Box>
</CardHeader>
<CardContent
sx={{
paddingInline: 1,
paddingTop: 1,
m: 0,
paddingBottom: "0 !important",
}}
>
<GridWrapper>
{/* Only show inner folders */}
{innerFolders.map((innerFolder) => (
<FolderComponent
key={innerFolder.full_path}
folder={innerFolder}
/>
))}
{innerFolders.length === 0 && (
<Box
sx={{
gridColumn: "1 / -1",
textAlign: "center",
color: "secondary.muted",
}}
>
No folders in this inbox.
</Box>
)}
</GridWrapper>
<SelectedStats />
</CardContent>
<FolderActionDesktopBar />
{/* <FolderActionsSpeedDial /> */}
</Card>
);
}
146 changes: 3 additions & 143 deletions frontend/src/routes/inbox/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,44 +8,31 @@ import {
TerminalIcon,
Trash2Icon,
} from "lucide-react";
import { useMemo, useState } from "react";
import { useState } from "react";
import {
Box,
BoxProps,
Card,
CardContent,
DialogContent,
IconButton,
Tooltip,
Typography,
useTheme,
} from "@mui/material";
import { useSuspenseQuery } from "@tanstack/react-query";
import { createFileRoute } from "@tanstack/react-router";

import { useConfig } from "@/api/config";
import { inboxQueryOptions } from "@/api/inbox";
import { MatchChip, StyledChip } from "@/components/common/chips";
import { Dialog } from "@/components/common/dialogs";
import {
FileTypeIcon,
FolderStatusIcon,
FolderTypeIcon,
InboxTypeIcon,
PenaltyTypeIcon,
SourceTypeIcon,
} from "@/components/common/icons";
import { PageWrapper } from "@/components/common/page";
import { CardHeader } from "@/components/frontpage/statsCard";
import {
FolderActionDesktopBar,
RefreshAllFoldersButton,
} from "@/components/inbox/actions";
import {
FolderComponent,
GridWrapper,
SelectedStats,
} from "@/components/inbox/fileTree";
import { RefreshAllFoldersButton } from "@/components/inbox/actions";
import { InboxCard } from "@/components/inbox/cards/inboxCard";
import { FolderSelectionProvider } from "@/components/inbox/folderSelectionContext";
import { Folder } from "@/pythonTypes";

Expand Down Expand Up @@ -163,133 +150,6 @@ function PageHeader({ inboxes, ...props }: { inboxes: Folder[] } & BoxProps) {
);
}

function InboxCard({ folder }: { folder: Folder }) {
const config = useConfig();

// configuration for this inbox folder
const folderConfig = useMemo<(typeof config)["gui"]["inbox"]["folders"][0]>(() => {
const fc = Object.entries(config.gui.inbox.folders).find(
([_k, v]) => v.path === folder.full_path
);

return fc
? fc[1]
: {
name: "Inbox",
autotag: false,
path: folder.full_path,
};
}, [config, folder.full_path]);

const innerFolders = useMemo(() => {
// Filter out folders that are not albums or files
return folder.children.filter((f) => f.type === "directory");
}, [folder.children]);

const threshold = folderConfig.auto_threshold ?? config.match.strong_rec_thresh;

let tooltip: string;
switch (folderConfig.autotag) {
case "auto":
tooltip =
"Automatic tagging and import enabled. " +
(1 - threshold) * 100 +
"% threshold.";
break;
case "preview":
tooltip = "Automatic tagging enabled, but no import.";
break;
case "bootleg":
tooltip = "Import as-is, and split albums by meta-data.";
break;
default:
tooltip = "No automatic tagging or import enabled.";
break;
}

return (
<Card sx={{ width: "100%", padding: 2 }}>
<CardHeader
key={folder.full_path}
icon={
<Tooltip title={tooltip}>
<InboxTypeIcon
size={24}
type={folderConfig.autotag || undefined}
/>
</Tooltip>
}
dividerPos="70%"
color="secondary.main"
>
<Box
sx={{
display: "flex",
alignItems: "flex-end",
width: "100%",
justifyContent: "space-between",
}}
>
<Typography
variant="body2"
sx={{
flexGrow: 1,
m: 0,
p: 0,
fontWeight: "bold",
paddingLeft: 2,
}}
>
{folderConfig.path.replaceAll("/", " / ")}
</Typography>
<Typography
variant="body1"
sx={{
fontWeight: "bold",
m: 0,
p: 0,
}}
>
{folderConfig.name}
</Typography>
</Box>
</CardHeader>
<CardContent
sx={{
paddingInline: 1,
paddingTop: 1,
m: 0,
paddingBottom: "0 !important",
}}
>
<GridWrapper>
{/* Only show inner folders */}
{innerFolders.map((innerFolder) => (
<FolderComponent
key={innerFolder.full_path}
folder={innerFolder}
/>
))}
{innerFolders.length === 0 && (
<Box
sx={{
gridColumn: "1 / -1",
textAlign: "center",
color: "secondary.muted",
}}
>
No folders in this inbox.
</Box>
)}
</GridWrapper>
<SelectedStats />
</CardContent>
<FolderActionDesktopBar />
{/* <FolderActionsSpeedDial /> */}
</Card>
);
}

/** Description of the inbox page, shown as modal on click */
function InfoDescription() {
const theme = useTheme();
Expand Down
Loading