Skip to content

Commit

Permalink
feat(plugin/organizer): improve usability
Browse files Browse the repository at this point in the history
  • Loading branch information
benjaminshafii committed Nov 9, 2024
1 parent 8e9d6bf commit a89ca56
Show file tree
Hide file tree
Showing 12 changed files with 116 additions and 114 deletions.
4 changes: 1 addition & 3 deletions plugin/views/ai-chat/chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,6 @@ export const ChatComponent: React.FC<ChatComponentProps> = ({
return `Path: ${file.path}\nTitle: ${file.title}\nReference: ${file.reference}\nContent:\n${file.content}`;
})
.join("\n\n-------\n\n");
console.log(contextString, "contextString");

const result = await streamText({
model: ollama("llama3.2"),
Expand All @@ -161,7 +160,7 @@ export const ChatComponent: React.FC<ChatComponentProps> = ({
return fetch(url, options);
},
onToolCall({ toolCall }) {
console.log("toolCall", toolCall);
logMessage("toolCall", toolCall);
},
keepLastMessageOnError: true,
onError: error => {
Expand Down Expand Up @@ -496,7 +495,6 @@ export const ChatComponent: React.FC<ChatComponentProps> = ({

const handleYouTubeTranscript = useCallback(
(transcript: string, title: string, videoId: string) => {
console.log(transcript, "this is the transcript");
setSelectedYouTubeVideos(prev => [
...prev,
{
Expand Down
1 change: 0 additions & 1 deletion plugin/views/organizer/ai-format/templates.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ export const ClassificationContainer: React.FC<ClassificationBoxProps> = ({
});
}

console.log("Content formatted successfully");
} catch (error) {
console.error("Error in handleFormat:", error);
}
Expand Down
1 change: 0 additions & 1 deletion plugin/views/organizer/chunks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ export const DocumentChunks: React.FC<DocumentChunksProps> = ({ plugin, activeFi
try {
const content = await plugin.app.vault.read(activeFile);
const result = await plugin.identifyConceptsAndFetchChunks(content);
console.log("result", result);
setConcepts(result.map(c => c.name));
setChunks(result.map(c => ({ concept: c.name, content: c.chunk })));
} catch (error) {
Expand Down
1 change: 0 additions & 1 deletion plugin/views/organizer/classification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ export const ClassificationContainer: React.FC<ClassificationBoxProps> = ({
formattingInstruction: formattingInstruction,
});

console.log("Content formatted successfully");
} catch (error) {
console.error("Error in handleFormat:", error);
}
Expand Down
49 changes: 49 additions & 0 deletions plugin/views/organizer/components/suggestion-buttons.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import * as React from "react";
import { motion } from "framer-motion";

// Base Folder Button Component
const BaseFolderButton: React.FC<{
folder: string;
onClick: (folder: string) => void;
className?: string;
score?: number;
reason?: string;
}> = ({ folder, onClick, className, score, reason }) => (
<motion.button
className={`px-3 py-1 rounded-md transition-colors duration-200 shadow-none ${className}`}
onClick={() => onClick(folder)}
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.8 }}
transition={{ duration: 0.2 }}
title={`Score: ${score}, Reason: ${reason}`}
>
{folder}
</motion.button>
);

// Existing Folder Button Component
export const ExistingFolderButton: React.FC<{
folder: string;
onClick: (folder: string) => void;
score: number;
reason: string;
}> = props => (
<BaseFolderButton
{...props}
className="bg-[--background-secondary] text-[--text-normal] hover:bg-[--interactive-accent] hover:text-[--text-on-accent] border border-solid border-[--background-modifier-border]"
/>
);

// New Folder Button Component
export const NewFolderButton: React.FC<{
folder: string;
onClick: (folder: string) => void;
score: number;
reason: string;
}> = props => (
<BaseFolderButton
{...props}
className="bg-[--background-secondary] text-[--text-normal] hover:bg-[--interactive-accent] hover:text-[--text-on-accent] border border-dashed border-[--text-muted]"
/>
);
82 changes: 42 additions & 40 deletions plugin/views/organizer/folders/box.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import FileOrganizer from "../../../index";
import { motion, AnimatePresence } from "framer-motion";
import { SkeletonLoader } from "../components/skeleton-loader";
import { FolderSuggestion } from "../../../index";
import { logMessage } from "../../../../utils";
import { ExistingFolderButton, NewFolderButton } from "../components/suggestion-buttons";

interface SimilarFolderBoxProps {
plugin: FileOrganizer;
Expand Down Expand Up @@ -34,22 +36,24 @@ export const SimilarFolderBox: React.FC<SimilarFolderBoxProps> = ({
content,
file.path
);

// Get all valid folders
const validFolders = plugin.getAllUserFolders();

// Filter suggestions to only include existing folders or new folders
const filteredSuggestions = folderSuggestions.filter(suggestion =>
suggestion.isNewFolder || validFolders.includes(suggestion.folder)
const filteredSuggestions = folderSuggestions.filter(
suggestion =>
suggestion.isNewFolder || validFolders.includes(suggestion.folder)
);

setSuggestions(filteredSuggestions);
} catch (err) {
console.error("Error fetching folders:", err);
const errorMessage = typeof err === 'object' && err !== null
? (err.error?.message || err.error || err.message || "Unknown error")
: String(err);

const errorMessage =
typeof err === "object" && err !== null
? err.error?.message || err.error || err.message || "Unknown error"
: String(err);

setError(new Error(errorMessage));
} finally {
setLoading(false);
Expand All @@ -66,27 +70,36 @@ export const SimilarFolderBox: React.FC<SimilarFolderBoxProps> = ({
};

const handleFolderClick = async (folder: string) => {
// if same folder, do nothing
logMessage({ newFolder: folder, currentFolder: file?.parent?.path });
if (folder === file?.parent?.path) return;
if (!file) return;

setLoading(true);
try {
await plugin.moveFile(file, file.basename, folder);
new Notice(`Moved ${file.basename} to ${folder}`);
} catch (error) {
console.error("Error moving file:", error);
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
new Notice(`Failed to move ${file.basename} to ${folder}: ${errorMessage}`);
const errorMessage =
error instanceof Error ? error.message : "Unknown error occurred";
new Notice(
`Failed to move ${file.basename} to ${folder}: ${errorMessage}`
);
} finally {
setLoading(false);
}
};
const filteredSuggestions = suggestions.filter(
s => s.folder !== file?.parent?.path
);

// Derive existing and new folders from suggestions
const existingFolders = suggestions.filter(s => !s.isNewFolder);
const newFolders = suggestions.filter(s => s.isNewFolder);
const existingFolders = filteredSuggestions.filter(s => !s.isNewFolder);
const newFolders = filteredSuggestions.filter(s => s.isNewFolder);

const renderError = () => (
<motion.div
<motion.div
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
className="space-y-3 rounded-md border-opacity-20"
Expand All @@ -101,17 +114,17 @@ export const SimilarFolderBox: React.FC<SimilarFolderBoxProps> = ({
</p>
</div>
</div>

<div className="flex items-center gap-3 text-sm">
<div className="flex gap-2">
<button
<button
onClick={handleRetry}
disabled={loading}
className="px-3 py-1.5 bg-[--interactive-accent] text-[--text-on-accent] rounded hover:bg-[--interactive-accent-hover] disabled:opacity-50 transition-colors duration-200"
>
{loading ? "Retrying..." : "Retry"}
</button>
<button
<button
onClick={() => setError(null)}
className="px-3 py-1.5 border border-[--background-modifier-border] rounded hover:bg-[--background-modifier-hover] transition-colors duration-200"
>
Expand Down Expand Up @@ -146,33 +159,22 @@ export const SimilarFolderBox: React.FC<SimilarFolderBoxProps> = ({
>
<AnimatePresence>
{existingFolders.map((folder, index) => (
<motion.button
<ExistingFolderButton
key={`existing-${index}`}
className="px-3 py-1 bg-[--background-secondary] text-[--text-normal] rounded-md hover:bg-[--interactive-accent] hover:text-white transition-colors duration-200"
onClick={() => handleFolderClick(folder.folder)}
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.8 }}
transition={{ duration: 0.2 }}
// add score as well
title={`Score of ${folder.score} because ${folder.reason} `}
>
{folder.folder}
</motion.button>
folder={folder.folder}
onClick={handleFolderClick}
score={folder.score}
reason={folder.reason}
/>
))}
{newFolders.map((folder, index) => (
<motion.button
<NewFolderButton
key={`new-${index}`}
className="px-3 py-1 bg-transparent border border-dashed border-[--text-muted] text-[--text-muted] rounded-md hover:bg-[--interactive-accent] hover:text-white hover:border-transparent transition-colors duration-200"
onClick={() => handleFolderClick(folder.folder)}
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.8 }}
transition={{ duration: 0.2 }}
title={`Score of ${folder.score} because ${folder.reason}`}
>
{folder.folder}
</motion.button>
folder={folder.folder}
onClick={handleFolderClick}
score={folder.score}
reason={folder.reason}
/>
))}
</AnimatePresence>
</motion.div>
Expand Down
58 changes: 8 additions & 50 deletions plugin/views/organizer/tags.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,53 +4,11 @@ import FileOrganizer from "../../index";
import { sanitizeTag } from "../../../utils";
import { SkeletonLoader } from "./components/skeleton-loader";
import { motion, AnimatePresence } from "framer-motion";
import { ExistingFolderButton, NewFolderButton } from "./components/suggestion-buttons";

// Base Tag Component
const BaseTag: React.FC<{
tag: string;
onClick: (tag: string) => void;
className?: string;
score?: number;
reason?: string;
}> = ({ tag, onClick, className, score, reason }) => (
<motion.span
className={`inline-block rounded px-2 py-1 text-sm cursor-pointer transition-colors duration-200 ${className}`}
onClick={() => onClick(tag)}
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.8 }}
transition={{ duration: 0.2 }}
title={`Score: ${score}, Reason: ${reason}`}
>
{sanitizeTag(tag)}
</motion.span>
);

// Existing Tag Component
const ExistingTag: React.FC<{
tag: string;
onClick: (tag: string) => void;
score: number;
reason: string;
}> = props => (
<BaseTag
{...props}
className="bg-[--background-secondary] text-[--text-normal] hover:text-[--text-on-accent] hover:bg-[--interactive-accent] hover:font-medium"
/>
);

// New Tag Component
const NewTag: React.FC<{
tag: string;
onClick: (tag: string) => void;
score: number;
reason: string;
}> = props => (
<BaseTag
{...props}
className="bg-transparent border border-dashed border-[--text-muted] text-[--text-muted] hover:text-[--text-on-accent] hover:bg-[--interactive-accent] hover:font-medium"
/>
);
// Rename the button components for tags
const ExistingTagButton = ExistingFolderButton;
const NewTagButton = NewFolderButton;

interface SimilarTagsProps {
plugin: FileOrganizer;
Expand Down Expand Up @@ -133,18 +91,18 @@ export const SimilarTags: React.FC<SimilarTagsProps> = ({
>
<AnimatePresence>
{existingTags.map((tag, index) => (
<ExistingTag
<ExistingTagButton
key={`existing-${index}`}
tag={tag.tag}
folder={sanitizeTag(tag.tag)}
onClick={handleTagClick}
score={tag.score}
reason={tag.reason}
/>
))}
{newTags.map((tag, index) => (
<NewTag
<NewTagButton
key={`new-${index}`}
tag={tag.tag}
folder={sanitizeTag(tag.tag)}
onClick={handleTagClick}
score={tag.score}
reason={tag.reason}
Expand Down
27 changes: 14 additions & 13 deletions plugin/views/organizer/titles/box.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import FileOrganizer from "../../../index";
import { z } from "zod";
import { motion, AnimatePresence } from "framer-motion";
import { SkeletonLoader } from "../components/skeleton-loader";
import { TitleSuggestion } from "./title-suggestion-item";
import { ExistingFolderButton } from "../components/suggestion-buttons";
import { logMessage } from "../../../../utils";

interface RenameSuggestionProps {
plugin: FileOrganizer;
Expand Down Expand Up @@ -41,7 +42,9 @@ export const RenameSuggestion: React.FC<RenameSuggestionProps> = ({

try {
const titles = await plugin.guessTitles(content, file.name);
setSuggestions(titles);
// remove current file name from suggestions
const filteredTitles = titles.filter(title => title.title !== file.name);
setSuggestions(filteredTitles);
} catch (err) {
console.error("Error fetching titles:", err);
const errorMessage = err instanceof Error ? err.message : "Unknown error";
Expand All @@ -56,6 +59,9 @@ export const RenameSuggestion: React.FC<RenameSuggestionProps> = ({
}, [suggestTitles, refreshKey]);

const handleTitleApply = async (title: string) => {
// if same title, do nothing
logMessage({ title, fileName: file?.basename });
if (title === file?.basename) return;
if (!file?.parent) return;

setLoading(true);
Expand Down Expand Up @@ -89,18 +95,13 @@ export const RenameSuggestion: React.FC<RenameSuggestionProps> = ({
>
<AnimatePresence>
{suggestions.map((suggestion, index) => (
<motion.button
<ExistingFolderButton
key={index}
className="px-3 py-1 bg-[--background-secondary] text-[--text-normal] rounded-md hover:bg-[--interactive-accent] hover:text-white transition-colors duration-200"
onClick={() => handleTitleApply(suggestion.title)}
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.8 }}
transition={{ duration: 0.2 }}
title={`Score of ${suggestion.score} because ${suggestion.reason}`}
>
{suggestion.title}
</motion.button>
folder={suggestion.title}
onClick={handleTitleApply}
score={suggestion.score}
reason={suggestion.reason}
/>
))}
</AnimatePresence>
</motion.div>
Expand Down
2 changes: 1 addition & 1 deletion plugin/views/organizer/view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ export const AssistantView: React.FC<AssistantViewProps> = ({
}

return (
<div className="tw-p-4 fo2k ">
<div className="tw-p-4 fo2k-cleaned">
<div className="flex gap-3 items-center">
<RefreshButton onRefresh={refreshContext} />
<div className="tw-mb-4">
Expand Down
Loading

0 comments on commit a89ca56

Please sign in to comment.