feat(profile-modal): Improvements - Show quality profile type in status page - Increase modal size, split things into columns - Filter formats - Bigger description size

This commit is contained in:
santiagosayshey
2024-08-24 03:47:36 +09:30
committed by Sam Chau
parent d9601eac0f
commit 1cee08bdbd
6 changed files with 215 additions and 107 deletions

View File

@@ -224,6 +224,8 @@ def determine_type(file_path):
return 'Regex Pattern'
elif 'custom_formats' in file_path:
return 'Custom Format'
elif 'profiles' in file_path:
return 'Quality Profile'
return 'Unknown'
def interpret_git_status(x, y):

View File

@@ -1,10 +1,11 @@
import { useState, useEffect } from "react";
import React, { useState, useEffect } from "react";
import FormatCard from "./FormatCard";
import FormatModal from "./FormatModal";
import AddNewCard from "../ui/AddNewCard";
import { getFormats } from "../../api/api";
import FilterMenu from "../ui/FilterMenu";
import SortMenu from "../ui/SortMenu";
import { Loader } from "lucide-react";
function FormatPage() {
const [formats, setFormats] = useState([]);
@@ -15,6 +16,15 @@ function FormatPage() {
const [filterValue, setFilterValue] = useState("");
const [allTags, setAllTags] = useState([]);
const [isCloning, setIsCloning] = useState(false);
const [isLoading, setIsLoading] = useState(true);
const loadingMessages = [
"Decoding the custom format matrix...",
"Parsing the digital alphabet soup...",
"Untangling the format spaghetti...",
"Calibrating the format-o-meter...",
"Indexing your media DNA...",
];
useEffect(() => {
fetchFormats();
@@ -30,6 +40,8 @@ function FormatPage() {
setAllTags(tags);
} catch (error) {
console.error("Error fetching formats:", error);
} finally {
setIsLoading(false);
}
};
@@ -86,6 +98,17 @@ function FormatPage() {
return 0;
});
if (isLoading) {
return (
<div className="flex flex-col items-center justify-center h-screen">
<Loader size={48} className="animate-spin text-blue-500 mb-4" />
<p className="text-lg font-medium text-gray-700 dark:text-gray-300">
{loadingMessages[Math.floor(Math.random() * loadingMessages.length)]}
</p>
</div>
);
}
return (
<div>
<h2 className="text-2xl font-bold mb-4">Manage Custom Formats</h2>

View File

@@ -25,6 +25,7 @@ function ProfileModal({
const [formatTags, setFormatTags] = useState([]);
const [tagScores, setTagScores] = useState({});
const [tagFilter, setTagFilter] = useState("");
const [formatFilter, setFormatFilter] = useState("");
const [error, setError] = useState("");
const [isDeleting, setIsDeleting] = useState(false);
const [loading, setLoading] = useState(true);
@@ -161,8 +162,12 @@ function ProfileModal({
tag.toLowerCase().includes(tagFilter.toLowerCase())
);
const filteredFormats = customFormats.filter((format) =>
format.name.toLowerCase().includes(formatFilter.toLowerCase())
);
return (
<Modal isOpen={isOpen} onClose={onClose} title={modalTitle}>
<Modal isOpen={isOpen} onClose={onClose} title={modalTitle} size="7xl">
{loading ? (
<div className="flex justify-center items-center">
<Loader size={24} className="animate-spin text-gray-300" />
@@ -170,117 +175,134 @@ function ProfileModal({
) : (
<>
{error && <div className="text-red-500 mb-4">{error}</div>}
<div className="mb-4">
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Profile Name
</label>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Enter profile name"
className="w-full p-2 border rounded dark:bg-gray-700 dark:text-gray-200 dark:border-gray-600"
/>
</div>
<div className="mb-4">
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Description
</label>
<textarea
value={description}
onChange={(e) => setDescription(e.target.value)}
placeholder="Enter description"
className="w-full p-2 border rounded dark:bg-gray-700 dark:text-gray-200 dark:border-gray-600"
rows="3"
/>
</div>
<div className="mb-4">
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Tags
</label>
<div className="flex flex-wrap mb-2">
{tags.map((tag) => (
<span
key={tag}
className="bg-blue-100 text-blue-800 text-xs font-medium mr-2 px-2.5 py-0.5 rounded dark:bg-blue-900 dark:text-blue-300"
>
{tag}
<div className="grid grid-cols-3 gap-4">
<div>
<div className="mb-4">
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Profile Name
</label>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Enter profile name"
className="w-full p-2 border rounded dark:bg-gray-700 dark:text-gray-200 dark:border-gray-600"
/>
</div>
<div className="mb-4">
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Description
</label>
<textarea
value={description}
onChange={(e) => setDescription(e.target.value)}
placeholder="Enter description"
className="w-full p-2 border rounded dark:bg-gray-700 dark:text-gray-200 dark:border-gray-600 resize-none"
rows="5"
/>
</div>
<div className="mb-4">
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Tags
</label>
<div className="flex flex-wrap mb-2">
{tags.map((tag) => (
<span
key={tag}
className="bg-blue-100 text-blue-800 text-xs font-medium mr-2 px-2.5 py-0.5 rounded dark:bg-blue-900 dark:text-blue-300"
>
{tag}
<button
onClick={() => handleRemoveTag(tag)}
className="ml-1 text-xs"
>
&times;
</button>
</span>
))}
</div>
<div className="flex">
<input
type="text"
value={newTag}
onChange={(e) => setNewTag(e.target.value)}
placeholder="Add a tag"
className="flex-grow p-2 border rounded-l dark:bg-gray-700 dark:text-gray-200 dark:border-gray-600"
/>
<button
onClick={() => handleRemoveTag(tag)}
className="ml-1 text-xs"
onClick={handleAddTag}
className="bg-blue-500 text-white px-4 py-2 rounded-r hover:bg-blue-600 transition-colors"
>
&times;
Add
</button>
</span>
))}
</div>
<div className="flex">
<input
type="text"
value={newTag}
onChange={(e) => setNewTag(e.target.value)}
placeholder="Add a tag"
className="flex-grow p-2 border rounded-l dark:bg-gray-700 dark:text-gray-200 dark:border-gray-600"
/>
<button
onClick={handleAddTag}
className="bg-blue-500 text-white px-4 py-2 rounded-r hover:bg-blue-600 transition-colors"
>
Add
</button>
</div>
</div>
<div className="mb-4">
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Custom Formats
</label>
<div className="max-h-60 overflow-y-auto">
{customFormats.map((format) => (
<div
key={format.id}
className="flex items-center space-x-2 mb-2"
>
<span className="flex-grow">{format.name}</span>
<input
type="number"
value={format.score}
onChange={(e) =>
handleScoreChange(format.id, e.target.value)
}
className="w-20 p-1 border rounded dark:bg-gray-700 dark:text-gray-200 dark:border-gray-600"
min="0"
/>
</div>
))}
</div>
</div>
</div>
<div className="mb-4">
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Tag-based Scoring
</label>
<input
type="text"
value={tagFilter}
onChange={(e) => setTagFilter(e.target.value)}
placeholder="Filter tags"
className="w-full p-2 border rounded mb-2 dark:bg-gray-700 dark:text-gray-200 dark:border-gray-600"
/>
<div className="max-h-60 overflow-y-auto">
{filteredTags.map((tag) => (
<div key={tag} className="flex items-center space-x-2 mb-2">
<span className="flex-grow">{tag}</span>
<input
type="number"
value={tagScores[tag]}
onChange={(e) => handleTagScoreChange(tag, e.target.value)}
className="w-20 p-1 border rounded dark:bg-gray-700 dark:text-gray-200 dark:border-gray-600"
min="0"
/>
<div>
<div className="mb-4">
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Custom Formats
</label>
<input
type="text"
value={formatFilter}
onChange={(e) => setFormatFilter(e.target.value)}
placeholder="Filter formats"
className="w-full p-2 border rounded mb-2 dark:bg-gray-700 dark:text-gray-200 dark:border-gray-600"
/>
<div className="max-h-96 overflow-y-auto">
{filteredFormats.map((format) => (
<div
key={format.id}
className="flex items-center space-x-2 mb-2"
>
<span className="flex-grow">{format.name}</span>
<input
type="number"
value={format.score}
onChange={(e) =>
handleScoreChange(format.id, e.target.value)
}
className="w-20 p-1 border rounded dark:bg-gray-700 dark:text-gray-200 dark:border-gray-600"
min="0"
/>
</div>
))}
</div>
))}
</div>
</div>
<div>
<div className="mb-4">
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Tag-based Scoring
</label>
<input
type="text"
value={tagFilter}
onChange={(e) => setTagFilter(e.target.value)}
placeholder="Filter tags"
className="w-full p-2 border rounded mb-2 dark:bg-gray-700 dark:text-gray-200 dark:border-gray-600"
/>
<div className="max-h-96 overflow-y-auto">
{filteredTags.map((tag) => (
<div key={tag} className="flex items-center space-x-2 mb-2">
<span className="flex-grow">{tag}</span>
<input
type="number"
value={tagScores[tag]}
onChange={(e) =>
handleTagScoreChange(tag, e.target.value)
}
className="w-20 p-1 border rounded dark:bg-gray-700 dark:text-gray-200 dark:border-gray-600"
min="0"
/>
</div>
))}
</div>
</div>
</div>
</div>
<div className="flex justify-between">
<div className="flex justify-between mt-4">
{initialProfile && (
<button
onClick={handleDelete}

View File

@@ -5,6 +5,7 @@ import AddNewCard from "../ui/AddNewCard";
import { getProfiles, getFormats } from "../../api/api";
import FilterMenu from "../ui/FilterMenu";
import SortMenu from "../ui/SortMenu";
import { Loader } from "lucide-react";
function ProfilePage() {
const [profiles, setProfiles] = useState([]);
@@ -16,6 +17,15 @@ function ProfilePage() {
const [filterValue, setFilterValue] = useState("");
const [allTags, setAllTags] = useState([]);
const [isCloning, setIsCloning] = useState(false);
const [isLoading, setIsLoading] = useState(true);
const loadingMessages = [
"Profiling your media collection...",
"Organizing your digital hoard...",
"Calibrating the flux capacitor...",
"Synchronizing with the movie matrix...",
"Optimizing your binge-watching potential...",
];
useEffect(() => {
fetchProfiles();
@@ -32,6 +42,8 @@ function ProfilePage() {
setAllTags(tags);
} catch (error) {
console.error("Error fetching profiles:", error);
} finally {
setIsLoading(false);
}
};
@@ -105,6 +117,17 @@ function ProfilePage() {
return 0;
});
if (isLoading) {
return (
<div className="flex flex-col items-center justify-center h-screen">
<Loader size={48} className="animate-spin text-blue-500 mb-4" />
<p className="text-lg font-medium text-gray-700 dark:text-gray-300">
{loadingMessages[Math.floor(Math.random() * loadingMessages.length)]}
</p>
</div>
);
}
return (
<div>
<h2 className="text-2xl font-bold mb-4">Manage Profiles</h2>

View File

@@ -1,10 +1,11 @@
import { useState, useEffect } from "react";
import React, { useState, useEffect } from "react";
import RegexCard from "./RegexCard";
import RegexModal from "./RegexModal";
import AddNewCard from "../ui/AddNewCard";
import { getRegexes } from "../../api/api";
import FilterMenu from "../ui/FilterMenu";
import SortMenu from "../ui/SortMenu";
import { Loader } from "lucide-react";
function RegexPage() {
const [regexes, setRegexes] = useState([]);
@@ -15,6 +16,15 @@ function RegexPage() {
const [filterValue, setFilterValue] = useState("");
const [allTags, setAllTags] = useState([]);
const [isCloning, setIsCloning] = useState(false);
const [isLoading, setIsLoading] = useState(true);
const loadingMessages = [
"Matching patterns in the digital universe...",
"Capturing groups of binary brilliance...",
"Escaping special characters in the wild...",
"Quantifying the unquantifiable...",
"Regex-ing the un-regex-able...",
];
useEffect(() => {
fetchRegexes();
@@ -30,6 +40,8 @@ function RegexPage() {
setAllTags(tags);
} catch (error) {
console.error("Error fetching regexes:", error);
} finally {
setIsLoading(false);
}
};
@@ -87,6 +99,17 @@ function RegexPage() {
return 0;
});
if (isLoading) {
return (
<div className="flex flex-col items-center justify-center h-screen">
<Loader size={48} className="animate-spin text-blue-500 mb-4" />
<p className="text-lg font-medium text-gray-700 dark:text-gray-300">
{loadingMessages[Math.floor(Math.random() * loadingMessages.length)]}
</p>
</div>
);
}
return (
<div>
<h2 className="text-2xl font-bold mb-4">Manage Regex Patterns</h2>

View File

@@ -67,6 +67,8 @@ function Modal({
"3xl": "max-w-3xl",
"4xl": "max-w-4xl",
"5xl": "max-w-5xl",
"6xl": "max-w-6xl",
"7xl": "max-w-7xl",
};
return (
@@ -91,6 +93,8 @@ function Modal({
style={{
zIndex: 1001 + level * 10,
minHeight: "300px",
maxHeight: "90vh",
overflowY: "auto",
}}
onClick={(e) => e.stopPropagation()}
>
@@ -130,7 +134,18 @@ Modal.propTypes = {
level: PropTypes.number,
disableCloseOnOutsideClick: PropTypes.bool,
disableCloseOnEscape: PropTypes.bool,
size: PropTypes.oneOf(["sm", "md", "lg", "xl", "2xl", "3xl", "4xl", "5xl"]),
size: PropTypes.oneOf([
"sm",
"md",
"lg",
"xl",
"2xl",
"3xl",
"4xl",
"5xl",
"6xl",
"7xl",
]),
};
export default Modal;