|
@@ -69,6 +69,7 @@ import { formatDateTime, formatDateOnly, parseUTCDate, type TimeFormat, formatDu
|
|
|
import { getCurrencySymbol } from '../utils/currency';
|
|
import { getCurrencySymbol } from '../utils/currency';
|
|
|
import { getBedTypeInfo } from '../utils/bedType';
|
|
import { getBedTypeInfo } from '../utils/bedType';
|
|
|
import { invalidateArchiveAndProjectViews } from '../utils/projectQueries';
|
|
import { invalidateArchiveAndProjectViews } from '../utils/projectQueries';
|
|
|
|
|
+import { assignableProjects } from '../utils/projectTree';
|
|
|
import { usePageFileDrop } from '../hooks/usePageFileDrop';
|
|
import { usePageFileDrop } from '../hooks/usePageFileDrop';
|
|
|
import type { Archive, PrintLogEntry, ProjectListItem } from '../api/client';
|
|
import type { Archive, PrintLogEntry, ProjectListItem } from '../api/client';
|
|
|
import { Card, CardContent } from '../components/Card';
|
|
import { Card, CardContent } from '../components/Card';
|
|
@@ -767,7 +768,7 @@ function ArchiveCard({
|
|
|
onClick: () => {},
|
|
onClick: () => {},
|
|
|
disabled: !canModify('archives', 'update', archive.created_by_id),
|
|
disabled: !canModify('archives', 'update', archive.created_by_id),
|
|
|
title: !canModify('archives', 'update', archive.created_by_id) ? t('archives.permission.noUpdateArchives') : undefined,
|
|
title: !canModify('archives', 'update', archive.created_by_id) ? t('archives.permission.noUpdateArchives') : undefined,
|
|
|
- submenuSearchPlaceholder: (projects?.filter(p => p.status === 'active').length ?? 0) > 5
|
|
|
|
|
|
|
+ submenuSearchPlaceholder: assignableProjects(projects ?? [], archive.project_id).length > 5
|
|
|
? t('archives.menu.searchProjects')
|
|
? t('archives.menu.searchProjects')
|
|
|
: undefined,
|
|
: undefined,
|
|
|
submenu: (() => {
|
|
submenu: (() => {
|
|
@@ -792,10 +793,14 @@ function ArchiveCard({
|
|
|
disabled: true,
|
|
disabled: true,
|
|
|
});
|
|
});
|
|
|
} else {
|
|
} else {
|
|
|
- const activeProjects = projects
|
|
|
|
|
- .filter(p => p.status === 'active')
|
|
|
|
|
|
|
+ // Archived projects are put away on purpose and are left out;
|
|
|
|
|
+ // completed ones stay, since a reprint filed against a finished
|
|
|
|
|
+ // project is ordinary (#2888). The archive's own project is kept
|
|
|
|
|
+ // whatever its status -- it is disabled below, and dropping it
|
|
|
|
|
+ // would leave the menu unable to say where the archive already is.
|
|
|
|
|
+ const assignable = assignableProjects(projects, archive.project_id)
|
|
|
.sort((a, b) => a.name.localeCompare(b.name));
|
|
.sort((a, b) => a.name.localeCompare(b.name));
|
|
|
- if (activeProjects.length === 0) {
|
|
|
|
|
|
|
+ if (assignable.length === 0) {
|
|
|
items.push({
|
|
items.push({
|
|
|
label: t('archives.menu.noProjectsAvailable'),
|
|
label: t('archives.menu.noProjectsAvailable'),
|
|
|
icon: <FolderKanban className="w-4 h-4 opacity-50" />,
|
|
icon: <FolderKanban className="w-4 h-4 opacity-50" />,
|
|
@@ -803,7 +808,7 @@ function ArchiveCard({
|
|
|
disabled: true,
|
|
disabled: true,
|
|
|
});
|
|
});
|
|
|
} else {
|
|
} else {
|
|
|
- activeProjects.forEach(p => {
|
|
|
|
|
|
|
+ assignable.forEach(p => {
|
|
|
items.push({
|
|
items.push({
|
|
|
label: p.name,
|
|
label: p.name,
|
|
|
icon: <div className="w-3 h-3 rounded-full flex-shrink-0" style={{ backgroundColor: p.color || '#888' }} />,
|
|
icon: <div className="w-3 h-3 rounded-full flex-shrink-0" style={{ backgroundColor: p.color || '#888' }} />,
|
|
@@ -2156,7 +2161,7 @@ function ArchiveListRow({
|
|
|
label: t('archives.menu.addToProject'),
|
|
label: t('archives.menu.addToProject'),
|
|
|
icon: <FolderKanban className="w-4 h-4" />,
|
|
icon: <FolderKanban className="w-4 h-4" />,
|
|
|
onClick: () => {},
|
|
onClick: () => {},
|
|
|
- submenuSearchPlaceholder: (projects?.filter(p => p.status === 'active').length ?? 0) > 5
|
|
|
|
|
|
|
+ submenuSearchPlaceholder: assignableProjects(projects ?? [], archive.project_id).length > 5
|
|
|
? t('archives.menu.searchProjects')
|
|
? t('archives.menu.searchProjects')
|
|
|
: undefined,
|
|
: undefined,
|
|
|
submenu: (() => {
|
|
submenu: (() => {
|
|
@@ -2176,10 +2181,14 @@ function ArchiveListRow({
|
|
|
disabled: true,
|
|
disabled: true,
|
|
|
});
|
|
});
|
|
|
} else {
|
|
} else {
|
|
|
- const activeProjects = projects
|
|
|
|
|
- .filter(p => p.status === 'active')
|
|
|
|
|
|
|
+ // Archived projects are put away on purpose and are left out;
|
|
|
|
|
+ // completed ones stay, since a reprint filed against a finished
|
|
|
|
|
+ // project is ordinary (#2888). The archive's own project is kept
|
|
|
|
|
+ // whatever its status -- it is disabled below, and dropping it
|
|
|
|
|
+ // would leave the menu unable to say where the archive already is.
|
|
|
|
|
+ const assignable = assignableProjects(projects, archive.project_id)
|
|
|
.sort((a, b) => a.name.localeCompare(b.name));
|
|
.sort((a, b) => a.name.localeCompare(b.name));
|
|
|
- if (activeProjects.length === 0) {
|
|
|
|
|
|
|
+ if (assignable.length === 0) {
|
|
|
items.push({
|
|
items.push({
|
|
|
label: t('archives.menu.noProjectsAvailable'),
|
|
label: t('archives.menu.noProjectsAvailable'),
|
|
|
icon: <FolderKanban className="w-4 h-4 opacity-50" />,
|
|
icon: <FolderKanban className="w-4 h-4 opacity-50" />,
|
|
@@ -2187,7 +2196,7 @@ function ArchiveListRow({
|
|
|
disabled: true,
|
|
disabled: true,
|
|
|
});
|
|
});
|
|
|
} else {
|
|
} else {
|
|
|
- activeProjects.forEach(p => {
|
|
|
|
|
|
|
+ assignable.forEach(p => {
|
|
|
items.push({
|
|
items.push({
|
|
|
label: p.name,
|
|
label: p.name,
|
|
|
icon: <div className="w-3 h-3 rounded-full flex-shrink-0" style={{ backgroundColor: p.color || '#888' }} />,
|
|
icon: <div className="w-3 h-3 rounded-full flex-shrink-0" style={{ backgroundColor: p.color || '#888' }} />,
|