test: add data-testid attributes to admin sub-components and modals
This commit is contained in:
@@ -54,7 +54,7 @@ export default function ConfirmationModal({
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40">
|
||||
<div data-testid="confirmation-modal" className="fixed inset-0 z-50 flex items-center justify-center bg-black/40">
|
||||
<div className="bg-surface border border-slate-800 rounded-lg shadow-xl max-w-sm w-full mx-4">
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between p-6 border-b border-slate-800">
|
||||
@@ -144,6 +144,7 @@ export default function ConfirmationModal({
|
||||
</button>
|
||||
<button
|
||||
onClick={handleConfirm}
|
||||
data-testid="confirm-action"
|
||||
disabled={loading || !canConfirm}
|
||||
className="flex-1 px-4 py-2.5 bg-rose-600 text-white rounded font-semibold hover:bg-rose-700 cursor-pointer transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2 focus:ring-2 focus:ring-offset-2 focus:ring-offset-slate-900 focus:ring-rose-600 focus:outline-none"
|
||||
>
|
||||
|
||||
@@ -70,7 +70,7 @@ export default function CreateUserModal({ show, onClose, onUserCreated }: Create
|
||||
const isFormValid = username.trim() && password.length >= 6 && !Object.keys(errors).length;
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40">
|
||||
<div data-testid="create-user-modal" className="fixed inset-0 z-50 flex items-center justify-center bg-black/40">
|
||||
<div className="bg-surface border border-slate-800 rounded-lg shadow-xl max-w-sm w-full mx-4">
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between p-6 border-b border-slate-800">
|
||||
@@ -93,6 +93,7 @@ export default function CreateUserModal({ show, onClose, onUserCreated }: Create
|
||||
</label>
|
||||
<input
|
||||
id="username"
|
||||
data-testid="new-user-name"
|
||||
type="text"
|
||||
value={username}
|
||||
onChange={(e) => {
|
||||
@@ -117,6 +118,7 @@ export default function CreateUserModal({ show, onClose, onUserCreated }: Create
|
||||
</label>
|
||||
<input
|
||||
id="password"
|
||||
data-testid="new-user-password"
|
||||
type="password"
|
||||
value={password}
|
||||
onChange={(e) => {
|
||||
@@ -146,6 +148,7 @@ export default function CreateUserModal({ show, onClose, onUserCreated }: Create
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
data-testid="create-user-submit"
|
||||
disabled={!isFormValid || loading}
|
||||
className="flex-1 px-4 py-2.5 bg-primary text-primary-foreground rounded font-semibold hover:bg-blue-600 transition-colors disabled:opacity-50 flex items-center justify-center gap-2 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-slate-900 focus-visible:ring-primary focus-visible:outline-none"
|
||||
>
|
||||
|
||||
@@ -32,7 +32,7 @@ export default function AiManager({
|
||||
onUpdatePrompt
|
||||
}: AiManagerProps) {
|
||||
return (
|
||||
<section className="bg-surface/50 border border-slate-800/50 rounded-[2.5rem] p-5 md:p-8 shadow-2xl space-y-6 transition-all group/ai">
|
||||
<section data-testid="ai-config" className="bg-surface/50 border border-slate-800/50 rounded-[2.5rem] p-5 md:p-8 shadow-2xl space-y-6 transition-all group/ai">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="w-10 h-10 rounded-xl bg-primary/10 flex items-center justify-center text-primary border border-primary/20">
|
||||
@@ -46,6 +46,7 @@ export default function AiManager({
|
||||
{aiConfig?.providers?.map((p: any) => (
|
||||
<button
|
||||
key={p.id}
|
||||
data-testid="provider-option"
|
||||
onClick={() => handleUpdateAiProvider(p.id)}
|
||||
className={cn(
|
||||
"p-4 rounded-2xl border transition-all text-left flex items-center justify-between group",
|
||||
@@ -91,6 +92,7 @@ export default function AiManager({
|
||||
<button
|
||||
onClick={onSaveAiKeys}
|
||||
disabled={isSavingKeys}
|
||||
data-testid="save-settings-button"
|
||||
className="px-6 py-2.5 bg-primary hover:bg-primary text-white rounded-xl text-sm font-black transition-all active:scale-95 shadow-xl shadow-primary/10 tracking-tight border border-primary/30 flex items-center gap-2"
|
||||
>
|
||||
{isSavingKeys ? <RotateCcw size={14} className="animate-spin" /> : <Lock size={14} />}
|
||||
@@ -103,6 +105,7 @@ export default function AiManager({
|
||||
<label className="text-sm font-bold text-secondary tracking-tight ml-1">Gemini Api Key</label>
|
||||
<div className="flex gap-2">
|
||||
<input
|
||||
data-testid="ai-api-key-input"
|
||||
type="password"
|
||||
value={aiKeys.gemini}
|
||||
onChange={(e) => setAiKeys({...aiKeys, gemini: e.target.value})}
|
||||
@@ -128,6 +131,7 @@ export default function AiManager({
|
||||
<label className="text-sm font-bold text-secondary tracking-tight ml-1">Claude Api Key</label>
|
||||
<div className="flex gap-2">
|
||||
<input
|
||||
data-testid="ai-api-key-input"
|
||||
type="password"
|
||||
value={aiKeys.claude}
|
||||
onChange={(e) => setAiKeys({...aiKeys, claude: e.target.value})}
|
||||
|
||||
@@ -31,17 +31,18 @@ export default function CategoryManager({
|
||||
</div>
|
||||
<h2 className="text-xl font-black text-white tracking-tight">Category Groups</h2>
|
||||
</div>
|
||||
<button
|
||||
<button
|
||||
onClick={onAddCategory}
|
||||
data-testid="add-category-button"
|
||||
className="flex items-center gap-2 bg-primary hover:bg-primary text-white px-6 py-3 rounded-xl text-sm font-black transition-all shadow-xl shadow-primary/10 active:scale-95 border border-primary/30 tracking-tight"
|
||||
>
|
||||
<Plus size={14} /> New Group
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="grid sm:grid-cols-2 lg:grid-cols-4 gap-3">
|
||||
<div data-testid="category-list" className="grid sm:grid-cols-2 lg:grid-cols-4 gap-3">
|
||||
{categories.map(cat => (
|
||||
<div key={cat.id} className="p-4 bg-background/40 border border-slate-800/50 rounded-2xl flex items-center justify-between group hover:border-primary/40 transition-all">
|
||||
<div key={cat.id} data-testid="category-item" className="p-4 bg-background/40 border border-slate-800/50 rounded-2xl flex items-center justify-between group hover:border-primary/40 transition-all">
|
||||
<div className="min-w-0 pr-4">
|
||||
<p className="card-title group-hover:text-primary transition-colors">{cat.name}</p>
|
||||
<p className="card-subtitle">{cat.description || 'General storage'}</p>
|
||||
@@ -56,8 +57,9 @@ export default function CategoryManager({
|
||||
>
|
||||
<Edit2 size={14} />
|
||||
</button>
|
||||
<button
|
||||
<button
|
||||
onClick={() => onDeleteCategory(cat.id, cat.name)}
|
||||
data-testid="delete-category-button"
|
||||
className="p-2 text-secondary hover:text-rose-500 hover:bg-rose-500/5 rounded-lg transition-all"
|
||||
>
|
||||
<Trash2 size={14} />
|
||||
@@ -82,11 +84,12 @@ export default function CategoryManager({
|
||||
<X size={20} />
|
||||
</button>
|
||||
</div>
|
||||
<div className="space-y-6">
|
||||
<div data-testid="category-form" className="space-y-6">
|
||||
<div className="space-y-1.5">
|
||||
<label className="text-sm font-bold text-secondary tracking-tight ml-1">Group Identifier</label>
|
||||
<input
|
||||
type="text"
|
||||
<input
|
||||
data-testid="category-name-input"
|
||||
type="text"
|
||||
value={editCatForm.name}
|
||||
onChange={(e) => setEditCatForm({...editCatForm, name: e.target.value})}
|
||||
className="w-full bg-background border border-slate-800 rounded-2xl py-3.5 px-5 text-sm text-white focus:border-primary outline-none transition-all"
|
||||
@@ -100,7 +103,7 @@ export default function CategoryManager({
|
||||
className="w-full bg-background border border-slate-800 rounded-2xl py-4 px-5 text-sm text-white focus:border-primary outline-none transition-all h-32 resize-none"
|
||||
/>
|
||||
</div>
|
||||
<button onClick={onUpdateCategorySubmit} className="w-full bg-primary hover:bg-primary text-white font-black py-4 rounded-2xl shadow-xl shadow-primary/20 active:scale-95 transition-all text-sm mb-4 tracking-tight">
|
||||
<button data-testid="add-category-submit" onClick={onUpdateCategorySubmit} className="w-full bg-primary hover:bg-primary text-white font-black py-4 rounded-2xl shadow-xl shadow-primary/20 active:scale-95 transition-all text-sm mb-4 tracking-tight">
|
||||
Update Asset Group
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -35,7 +35,7 @@ export default function DatabaseManager({
|
||||
|
||||
return (
|
||||
<div className="space-y-6 md:space-y-8 h-full">
|
||||
<div className="bg-surface/50 border border-slate-800/50 rounded-[2.5rem] p-5 md:p-8 shadow-2xl overflow-hidden relative group transition-all">
|
||||
<div data-testid="database-info" className="bg-surface/50 border border-slate-800/50 rounded-[2.5rem] p-5 md:p-8 shadow-2xl overflow-hidden relative group transition-all">
|
||||
<div className="flex items-center gap-4 mb-6">
|
||||
<div className="w-10 h-10 rounded-xl bg-primary/10 flex items-center justify-center text-primary border border-primary/20">
|
||||
<Database size={20} />
|
||||
@@ -59,6 +59,7 @@ export default function DatabaseManager({
|
||||
<button
|
||||
onClick={onCreateBackup}
|
||||
disabled={isBackingUp}
|
||||
data-testid="backup-button"
|
||||
className="flex items-center gap-2 px-5 py-3 bg-primary hover:bg-blue-600 text-white rounded-xl text-sm font-black transition-all active:scale-95 disabled:opacity-50 shadow-xl shadow-primary/10 tracking-tight focus-visible:ring-2 focus-visible:ring-primary focus-visible:outline-none"
|
||||
aria-label="Create database backup"
|
||||
>
|
||||
|
||||
@@ -34,6 +34,7 @@ export default function IdentityManager({
|
||||
</div>
|
||||
<button
|
||||
onClick={onAddUser}
|
||||
data-testid="add-user-button"
|
||||
className="flex items-center gap-2 px-5 py-2.5 bg-primary hover:bg-blue-600 text-white rounded-xl text-sm font-black transition-all shadow-xl shadow-primary/10 active:scale-95 border border-primary/30 tracking-tight focus-visible:ring-2 focus-visible:ring-primary focus-visible:outline-none"
|
||||
aria-label="Add new user"
|
||||
>
|
||||
@@ -70,6 +71,7 @@ export default function IdentityManager({
|
||||
{user.username !== 'Admin' && (
|
||||
<button
|
||||
onClick={() => onDeleteUser(user.id, user.username)}
|
||||
data-testid="delete-user-button"
|
||||
className="p-2 text-secondary hover:text-rose-500 hover:bg-rose-500/5 rounded-xl transition-all focus-visible:ring-2 focus-visible:ring-rose-500 focus-visible:outline-none"
|
||||
aria-label={`Delete user ${user.username}`}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user