mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-08 23:21:58 +02:00
Merge pull request #8 from cadtoolbox/copilot/hide-uploaded-by-column
This commit is contained in:
@@ -614,4 +614,115 @@ describe('FileManagerPage', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('authentication-based UI changes', () => {
|
||||
it('hides "Uploaded By" column and user filter when auth is disabled', async () => {
|
||||
// Mock auth disabled (default)
|
||||
server.use(
|
||||
http.get('*/api/v1/auth/status', () => {
|
||||
return HttpResponse.json({
|
||||
auth_enabled: false,
|
||||
requires_setup: false,
|
||||
});
|
||||
}),
|
||||
http.get('/api/v1/library/files', () => {
|
||||
return HttpResponse.json([
|
||||
{
|
||||
id: 1,
|
||||
filename: 'test.3mf',
|
||||
file_path: '/library/test.3mf',
|
||||
file_size: 1048576,
|
||||
file_type: '3mf',
|
||||
folder_id: null,
|
||||
thumbnail_path: null,
|
||||
print_name: 'Test File',
|
||||
print_time_seconds: 3600,
|
||||
print_count: 0,
|
||||
duplicate_count: 0,
|
||||
created_at: '2024-01-01T00:00:00Z',
|
||||
created_by_username: 'testuser',
|
||||
},
|
||||
]);
|
||||
})
|
||||
);
|
||||
|
||||
render(<FileManagerPage />);
|
||||
|
||||
// Switch to list view to see the column headers
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Test File')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
const user = userEvent.setup();
|
||||
const listViewButton = screen.getByRole('button', { name: /list/i });
|
||||
await user.click(listViewButton);
|
||||
|
||||
// "Uploaded By" column header should not be present
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText('Uploaded By')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
// User filter dropdown should not be present
|
||||
expect(screen.queryByPlaceholderText('Filter by user')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows "Uploaded By" column and user filter when auth is enabled', async () => {
|
||||
// Mock auth enabled
|
||||
server.use(
|
||||
http.get('*/api/v1/auth/status', () => {
|
||||
return HttpResponse.json({
|
||||
auth_enabled: true,
|
||||
requires_setup: false,
|
||||
});
|
||||
}),
|
||||
http.get('/api/v1/library/files', () => {
|
||||
return HttpResponse.json([
|
||||
{
|
||||
id: 1,
|
||||
filename: 'test.3mf',
|
||||
file_path: '/library/test.3mf',
|
||||
file_size: 1048576,
|
||||
file_type: '3mf',
|
||||
folder_id: null,
|
||||
thumbnail_path: null,
|
||||
print_name: 'Test File',
|
||||
print_time_seconds: 3600,
|
||||
print_count: 0,
|
||||
duplicate_count: 0,
|
||||
created_at: '2024-01-01T00:00:00Z',
|
||||
created_by_username: 'testuser',
|
||||
},
|
||||
]);
|
||||
}),
|
||||
http.get('/api/v1/users/', () => {
|
||||
return HttpResponse.json([
|
||||
{ id: 1, username: 'testuser' },
|
||||
{ id: 2, username: 'admin' },
|
||||
]);
|
||||
})
|
||||
);
|
||||
|
||||
render(<FileManagerPage />);
|
||||
|
||||
// Switch to list view to see the column headers
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Test File')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
const user = userEvent.setup();
|
||||
const listViewButton = screen.getByRole('button', { name: /list/i });
|
||||
await user.click(listViewButton);
|
||||
|
||||
// "Uploaded By" column header should be present
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Uploaded By')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
// User filter dropdown should be present
|
||||
expect(screen.getByPlaceholderText('Filter by user')).toBeInTheDocument();
|
||||
|
||||
// Username should be displayed in the column
|
||||
expect(screen.getByText('testuser')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -912,10 +912,11 @@ interface FileCardProps {
|
||||
thumbnailVersion?: number;
|
||||
hasPermission: (permission: Permission) => boolean;
|
||||
canModify: (resource: 'queue' | 'archives' | 'library', action: 'update' | 'delete' | 'reprint', createdById: number | null | undefined) => boolean;
|
||||
authEnabled: boolean;
|
||||
t: TFunction;
|
||||
}
|
||||
|
||||
function FileCard({ file, isSelected, isMobile, onSelect, onDelete, onDownload, onAddToQueue, onPrint, onRename, onGenerateThumbnail, thumbnailVersion, hasPermission, canModify, t }: FileCardProps) {
|
||||
function FileCard({ file, isSelected, isMobile, onSelect, onDelete, onDownload, onAddToQueue, onPrint, onRename, onGenerateThumbnail, thumbnailVersion, hasPermission, canModify, authEnabled, t }: FileCardProps) {
|
||||
const [showActions, setShowActions] = useState(false);
|
||||
|
||||
return (
|
||||
@@ -974,7 +975,7 @@ function FileCard({ file, isSelected, isMobile, onSelect, onDelete, onDownload,
|
||||
{t('fileManager.printedCount', { count: file.print_count })}
|
||||
</div>
|
||||
)}
|
||||
{file.created_by_username && (
|
||||
{authEnabled && file.created_by_username && (
|
||||
<div className="mt-1 text-xs text-bambu-gray flex items-center gap-1">
|
||||
<User className="w-3 h-3" />
|
||||
{file.created_by_username}
|
||||
@@ -1089,7 +1090,7 @@ export function FileManagerPage() {
|
||||
const { t } = useTranslation();
|
||||
const queryClient = useQueryClient();
|
||||
const { showToast } = useToast();
|
||||
const { hasPermission, hasAnyPermission, canModify } = useAuth();
|
||||
const { hasPermission, hasAnyPermission, canModify, authEnabled } = useAuth();
|
||||
const [searchParams] = useSearchParams();
|
||||
|
||||
// Read folder ID from URL query parameter
|
||||
@@ -1762,31 +1763,33 @@ export function FileManagerPage() {
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{/* Username filter with autocomplete */}
|
||||
<div className="relative">
|
||||
<input
|
||||
type="text"
|
||||
placeholder={t('fileManager.filterByUser', { defaultValue: 'Filter by user' })}
|
||||
value={filterUsername}
|
||||
onChange={(e) => setFilterUsername(e.target.value)}
|
||||
list="usernames-list"
|
||||
className={`w-32 sm:w-40 px-2 py-1.5 bg-bambu-dark border border-bambu-dark-tertiary rounded text-sm text-white placeholder-bambu-gray focus:outline-none focus:border-bambu-green ${filterUsername ? 'pr-7' : ''}`}
|
||||
style={filterUsername ? { WebkitAppearance: 'none', MozAppearance: 'textfield' } : undefined}
|
||||
/>
|
||||
{filterUsername && (
|
||||
<button
|
||||
onClick={() => setFilterUsername('')}
|
||||
className="absolute right-2 top-1/2 -translate-y-1/2 text-bambu-gray hover:text-white z-10"
|
||||
>
|
||||
<X className="w-3 h-3" />
|
||||
</button>
|
||||
)}
|
||||
<datalist id="usernames-list">
|
||||
{users?.map((user) => (
|
||||
<option key={user.id} value={user.username} />
|
||||
))}
|
||||
</datalist>
|
||||
</div>
|
||||
{/* Username filter with autocomplete - only show when auth is enabled */}
|
||||
{authEnabled && (
|
||||
<div className="relative">
|
||||
<input
|
||||
type="text"
|
||||
placeholder={t('fileManager.filterByUser', { defaultValue: 'Filter by user' })}
|
||||
value={filterUsername}
|
||||
onChange={(e) => setFilterUsername(e.target.value)}
|
||||
list="usernames-list"
|
||||
className={`w-32 sm:w-40 px-2 py-1.5 bg-bambu-dark border border-bambu-dark-tertiary rounded text-sm text-white placeholder-bambu-gray focus:outline-none focus:border-bambu-green ${filterUsername ? 'pr-7' : ''}`}
|
||||
style={filterUsername ? { WebkitAppearance: 'none', MozAppearance: 'textfield' } : undefined}
|
||||
/>
|
||||
{filterUsername && (
|
||||
<button
|
||||
onClick={() => setFilterUsername('')}
|
||||
className="absolute right-2 top-1/2 -translate-y-1/2 text-bambu-gray hover:text-white z-10"
|
||||
>
|
||||
<X className="w-3 h-3" />
|
||||
</button>
|
||||
)}
|
||||
<datalist id="usernames-list">
|
||||
{users?.map((user) => (
|
||||
<option key={user.id} value={user.username} />
|
||||
))}
|
||||
</datalist>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Sort */}
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -1995,6 +1998,7 @@ export function FileManagerPage() {
|
||||
thumbnailVersion={thumbnailVersions[file.id]}
|
||||
hasPermission={hasPermission}
|
||||
canModify={canModify}
|
||||
authEnabled={authEnabled}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
@@ -2003,10 +2007,10 @@ export function FileManagerPage() {
|
||||
<div className="flex-1 lg:overflow-y-auto">
|
||||
<div className="bg-bambu-dark-secondary rounded-lg border border-bambu-dark-tertiary overflow-hidden">
|
||||
{/* List header - hidden on mobile, show simplified on small screens */}
|
||||
<div className="hidden sm:grid grid-cols-[auto_1fr_120px_100px_100px_100px_80px] gap-4 px-4 py-2 bg-bambu-dark-secondary border-b border-bambu-dark-tertiary text-xs text-bambu-gray font-medium">
|
||||
<div className={`hidden sm:grid ${authEnabled ? 'grid-cols-[auto_1fr_120px_100px_100px_100px_80px]' : 'grid-cols-[auto_1fr_100px_100px_100px_80px]'} gap-4 px-4 py-2 bg-bambu-dark-secondary border-b border-bambu-dark-tertiary text-xs text-bambu-gray font-medium`}>
|
||||
<div className="w-6" />
|
||||
<div>{t('common.name')}</div>
|
||||
<div>{t('fileManager.uploadedBy', { defaultValue: 'Uploaded By' })}</div>
|
||||
{authEnabled && <div>{t('fileManager.uploadedBy', { defaultValue: 'Uploaded By' })}</div>}
|
||||
<div>{t('common.type')}</div>
|
||||
<div>{t('fileManager.size')}</div>
|
||||
<div>{t('fileManager.prints')}</div>
|
||||
@@ -2016,7 +2020,7 @@ export function FileManagerPage() {
|
||||
{filteredAndSortedFiles.map((file) => (
|
||||
<div
|
||||
key={file.id}
|
||||
className={`grid grid-cols-[auto_1fr_120px_100px_100px_100px_80px] gap-4 px-4 py-3 items-center border-b border-bambu-dark-tertiary last:border-b-0 cursor-pointer hover:bg-bambu-dark/50 transition-colors ${
|
||||
className={`grid ${authEnabled ? 'grid-cols-[auto_1fr_120px_100px_100px_100px_80px]' : 'grid-cols-[auto_1fr_100px_100px_100px_80px]'} gap-4 px-4 py-3 items-center border-b border-bambu-dark-tertiary last:border-b-0 cursor-pointer hover:bg-bambu-dark/50 transition-colors ${
|
||||
selectedFiles.includes(file.id) ? 'bg-bambu-green/10' : ''
|
||||
}`}
|
||||
onClick={() => handleFileSelect(file.id)}
|
||||
@@ -2062,17 +2066,19 @@ export function FileManagerPage() {
|
||||
<div className="text-sm text-white truncate">{file.print_name || file.filename}</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* Uploaded By */}
|
||||
<div className="text-sm text-bambu-gray flex items-center gap-1">
|
||||
{file.created_by_username ? (
|
||||
<>
|
||||
<User className="w-3 h-3" />
|
||||
<span className="truncate">{file.created_by_username}</span>
|
||||
</>
|
||||
) : (
|
||||
'-'
|
||||
)}
|
||||
</div>
|
||||
{/* Uploaded By - only show when auth is enabled */}
|
||||
{authEnabled && (
|
||||
<div className="text-sm text-bambu-gray flex items-center gap-1">
|
||||
{file.created_by_username ? (
|
||||
<>
|
||||
<User className="w-3 h-3" />
|
||||
<span className="truncate">{file.created_by_username}</span>
|
||||
</>
|
||||
) : (
|
||||
'-'
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{/* Type */}
|
||||
<div>
|
||||
<span className={`text-xs px-1.5 py-0.5 rounded font-medium ${
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2
-2
@@ -23,8 +23,8 @@
|
||||
|
||||
<!-- Splash screens for iOS -->
|
||||
<link rel="apple-touch-startup-image" href="/img/android-chrome-512x512.png" />
|
||||
<script type="module" crossorigin src="/assets/index-BaTXGNB2.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-BmrIrAHa.css">
|
||||
<script type="module" crossorigin src="/assets/index-kl_IYtg7.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-B7d6gcUW.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
Reference in New Issue
Block a user