@tuturuuu/ui 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +88 -0
- package/biome.json +1 -1
- package/package.json +75 -73
- package/src/components/ui/accordion.tsx +1 -1
- package/src/components/ui/breadcrumb.tsx +1 -1
- package/src/components/ui/calendar-app/calendar-page-shell.tsx +4 -0
- package/src/components/ui/calendar-app/components/calendar-connections-settings-content.tsx +239 -33
- package/src/components/ui/calendar-app/components/load-smart-scheduling-tasks.tsx +143 -0
- package/src/components/ui/calendar-app/components/priority-view.tsx +10 -3
- package/src/components/ui/calendar-app/components/tasks-sidebar.tsx +4 -116
- package/src/components/ui/calendar-app/components/use-calendar-connections-manager.ts +67 -2
- package/src/components/ui/calendar.tsx +1 -1
- package/src/components/ui/carousel.tsx +1 -1
- package/src/components/ui/chat/chat-agent-details-external-thread-panel.test.tsx +1 -1
- package/src/components/ui/chat/chat-agent-details-external-thread-panel.tsx +1 -1
- package/src/components/ui/chat/chat-agent-details-operations-panel.test.tsx +1 -1
- package/src/components/ui/chat/chat-agent-details-operations-panel.tsx +1 -1
- package/src/components/ui/chat/chat-agent-details-setup-panel.tsx +1 -1
- package/src/components/ui/chat/chat-agent-details-sidebar.test.tsx +1 -1
- package/src/components/ui/chat/chat-agent-details-sidebar.tsx +2 -2
- package/src/components/ui/chat/chat-agent-details-utils.test.ts +1 -1
- package/src/components/ui/chat/chat-agent-details-utils.tsx +1 -1
- package/src/components/ui/chat/chat-agent-details-zalo-personal-panel.tsx +2 -2
- package/src/components/ui/checkbox.tsx +1 -1
- package/src/components/ui/color-picker.tsx +1 -1
- package/src/components/ui/command.tsx +1 -1
- package/src/components/ui/context-menu.tsx +5 -1
- package/src/components/ui/currency-input.test.tsx +43 -0
- package/src/components/ui/currency-input.tsx +1 -1
- package/src/components/ui/custom/__tests__/settings-dialog-shell.test.tsx +3 -0
- package/src/components/ui/custom/__tests__/workspace-select-helpers.test.ts +19 -0
- package/src/components/ui/custom/combobox.test.tsx +195 -0
- package/src/components/ui/custom/combobox.tsx +273 -156
- package/src/components/ui/custom/education/modules/youtube/delete-link-button.tsx +5 -13
- package/src/components/ui/custom/facebook-mockup/facebook-mockup.tsx +7 -1
- package/src/components/ui/custom/facebook-mockup/form.tsx +1 -1
- package/src/components/ui/custom/facebook-mockup/image-upload-field.tsx +1 -1
- package/src/components/ui/custom/facebook-mockup/preview.tsx +1 -1
- package/src/components/ui/custom/settings-dialog-shell.tsx +2 -1
- package/src/components/ui/custom/theme-toggle.tsx +1 -1
- package/src/components/ui/custom/workspace-access/workspace-access-default-role-card.tsx +60 -35
- package/src/components/ui/custom/workspace-access/workspace-access-member-row.tsx +176 -167
- package/src/components/ui/custom/workspace-access/workspace-access-members.tsx +16 -10
- package/src/components/ui/custom/workspace-access/workspace-access-page-header.tsx +75 -36
- package/src/components/ui/custom/workspace-access/workspace-access-page.tsx +39 -42
- package/src/components/ui/custom/workspace-access/workspace-access-people-filters.tsx +1 -1
- package/src/components/ui/custom/workspace-access/workspace-access-roles.tsx +113 -91
- package/src/components/ui/custom/workspace-access/workspace-access-tabs-toolbar.tsx +73 -32
- package/src/components/ui/custom/workspace-select.tsx +8 -3
- package/src/components/ui/dialog.test.tsx +52 -0
- package/src/components/ui/dialog.tsx +6 -2
- package/src/components/ui/dropdown-menu.tsx +5 -1
- package/src/components/ui/finance/debts/debt-loan-form.tsx +12 -5
- package/src/components/ui/finance/debts/debt-loan-summary.tsx +3 -2
- package/src/components/ui/finance/debts/debts-page.test.tsx +54 -5
- package/src/components/ui/finance/debts/debts-page.tsx +15 -2
- package/src/components/ui/finance/invoices/components/subscription-group-selector.tsx +3 -5
- package/src/components/ui/finance/invoices/new-invoice-page.test.tsx +25 -5
- package/src/components/ui/finance/invoices/new-invoice-page.tsx +7 -2
- package/src/components/ui/finance/invoices/standard-invoice.tsx +4 -2
- package/src/components/ui/finance/invoices/subscription-invoice.tsx +4 -2
- package/src/components/ui/finance/invoices/utils.ts +3 -1
- package/src/components/ui/finance/transactions/form-content-dialog.tsx +3 -0
- package/src/components/ui/finance/transactions/form-types.ts +3 -0
- package/src/components/ui/finance/transactions/form.tsx +2 -0
- package/src/components/ui/finance/transactions/infinite-transactions-list.tsx +2 -0
- package/src/components/ui/finance/transactions/period-charts/category-breakdown-dialog.tsx +1 -1
- package/src/components/ui/finance/transactions/transaction-card.tsx +21 -9
- package/src/components/ui/finance/transactions/transaction-edit-dialog.tsx +1 -4
- package/src/components/ui/finance/transactions/transactions-create-summary.tsx +3 -0
- package/src/components/ui/finance/transactions/transactions-page.tsx +4 -1
- package/src/components/ui/finance/wallets/form.test.tsx +51 -3
- package/src/components/ui/finance/wallets/form.tsx +15 -4
- package/src/components/ui/finance/wallets/walletId/wallet-details-actions.tsx +4 -0
- package/src/components/ui/finance/wallets/walletId/wallet-details-page.tsx +4 -2
- package/src/components/ui/finance/wallets/wallets-data-table.tsx +1 -0
- package/src/components/ui/finance/wallets/wallets-page.tsx +5 -2
- package/src/components/ui/input-otp.tsx +1 -1
- package/src/components/ui/legacy/calendar/all-day-event-bar.tsx +28 -39
- package/src/components/ui/legacy/calendar/calendar-cell.tsx +2 -0
- package/src/components/ui/legacy/calendar/calendar-content.tsx +10 -6
- package/src/components/ui/legacy/calendar/calendar-header.tsx +23 -3
- package/src/components/ui/legacy/calendar/calendar-loading-skeleton.tsx +135 -0
- package/src/components/ui/legacy/calendar/calendar-matrix.tsx +175 -237
- package/src/components/ui/legacy/calendar/event-card.test.tsx +177 -0
- package/src/components/ui/legacy/calendar/event-card.tsx +220 -131
- package/src/components/ui/legacy/calendar/event-modal.tsx +17 -17
- package/src/components/ui/legacy/calendar/event-provider-display.tsx +69 -0
- package/src/components/ui/legacy/calendar/smart-calendar.test.tsx +86 -4
- package/src/components/ui/legacy/calendar/smart-calendar.tsx +32 -2
- package/src/components/ui/legacy/meet/create-plan-dialog.tsx +19 -10
- package/src/components/ui/money-input.test.tsx +64 -0
- package/src/components/ui/money-input.tsx +63 -0
- package/src/components/ui/navigation-menu.tsx +1 -1
- package/src/components/ui/pagination.tsx +1 -1
- package/src/components/ui/radio-group.tsx +1 -1
- package/src/components/ui/select.tsx +5 -1
- package/src/components/ui/sheet.tsx +1 -1
- package/src/components/ui/sidebar.tsx +1 -1
- package/src/components/ui/storefront/cart-popover.tsx +61 -0
- package/src/components/ui/storefront/cart-summary-parts.tsx +290 -0
- package/src/components/ui/storefront/cart-summary.tsx +104 -80
- package/src/components/ui/storefront/checkout-overlay.tsx +26 -0
- package/src/components/ui/storefront/hero-panel.tsx +2 -8
- package/src/components/ui/storefront/image-panel.tsx +6 -0
- package/src/components/ui/storefront/index.ts +11 -0
- package/src/components/ui/storefront/listing-card.tsx +84 -22
- package/src/components/ui/storefront/merch-sections.tsx +70 -0
- package/src/components/ui/storefront/product-detail.tsx +289 -0
- package/src/components/ui/storefront/product-dialog.tsx +72 -0
- package/src/components/ui/storefront/storefront-surface.test.tsx +221 -3
- package/src/components/ui/storefront/storefront-surface.tsx +288 -153
- package/src/components/ui/storefront/types.ts +27 -1
- package/src/components/ui/storefront/utils.ts +117 -27
- package/src/components/ui/text-editor/__tests__/content-migration.test.ts +32 -0
- package/src/components/ui/text-editor/__tests__/extensions.test.ts +123 -0
- package/src/components/ui/text-editor/__tests__/image-extension.test.ts +69 -1
- package/src/components/ui/text-editor/__tests__/video-extension.test.ts +47 -0
- package/src/components/ui/text-editor/background-color-extension.ts +62 -0
- package/src/components/ui/text-editor/color-controls.tsx +284 -0
- package/src/components/ui/text-editor/content-migration.ts +41 -18
- package/src/components/ui/text-editor/editor.tsx +69 -14
- package/src/components/ui/text-editor/extensions.ts +9 -3
- package/src/components/ui/text-editor/highlight-extension.ts +22 -0
- package/src/components/ui/text-editor/image-extension.ts +40 -18
- package/src/components/ui/text-editor/tool-bar.tsx +9 -16
- package/src/components/ui/text-editor/video-extension.ts +11 -2
- package/src/components/ui/toast.tsx +1 -1
- package/src/components/ui/tu-do/boards/__tests__/board-share-dialog.test.tsx +270 -0
- package/src/components/ui/tu-do/boards/__tests__/workspace-projects-client-page.test.tsx +70 -1
- package/src/components/ui/tu-do/boards/board-public-link-section.tsx +231 -0
- package/src/components/ui/tu-do/boards/board-share-dialog.tsx +222 -109
- package/src/components/ui/tu-do/boards/boardId/board-column-external-retry.test.tsx +127 -0
- package/src/components/ui/tu-do/boards/boardId/board-column.tsx +113 -46
- package/src/components/ui/tu-do/boards/boardId/kanban/bulk/bulk-mutations-clear-delete.ts +2 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/bulk/bulk-mutations-move.ts +5 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/bulk/bulk-mutations-updates.ts +3 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/data/kanban-deadline-query.ts +50 -2
- package/src/components/ui/tu-do/boards/boardId/kanban/dnd/__tests__/column-reorder.test.ts +17 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/dnd/column-reorder.ts +4 -1
- package/src/components/ui/tu-do/boards/boardId/kanban/dnd/task-drag-cache.ts +51 -9
- package/src/components/ui/tu-do/boards/boardId/kanban/dnd/task-drag-order.ts +2 -8
- package/src/components/ui/tu-do/boards/boardId/kanban/dnd/task-sort-key.ts +47 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/dnd/use-kanban-dnd.test.ts +63 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/dnd/use-kanban-dnd.ts +127 -38
- package/src/components/ui/tu-do/boards/boardId/kanban/planner/__tests__/kanban-planner-island.test.tsx +380 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/planner/kanban-planner-dialog.tsx +204 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/planner/planner-digest-panel.tsx +61 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/planner/planner-item-strip.tsx +54 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/planner/planner-plan-toolbar.tsx +251 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/planner/planner-scope-badge.tsx +27 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/planner/planner-section.tsx +58 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/planner/planner-share-dialog.tsx +238 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/planner/planner-target-controls.tsx +143 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/planner/planner-utils.ts +65 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/planner/use-kanban-planner-state.ts +234 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/rendering/kanban-columns.test.tsx +410 -4
- package/src/components/ui/tu-do/boards/boardId/kanban/rendering/kanban-columns.tsx +106 -14
- package/src/components/ui/tu-do/boards/boardId/kanban/rendering/kanban-deadline-panels.tsx +443 -19
- package/src/components/ui/tu-do/boards/boardId/kanban/rendering/kanban-skeleton.tsx +94 -32
- package/src/components/ui/tu-do/boards/boardId/kanban.tsx +213 -106
- package/src/components/ui/tu-do/boards/boardId/task-board-server-page.test.tsx +186 -0
- package/src/components/ui/tu-do/boards/boardId/task-board-server-page.tsx +59 -2
- package/src/components/ui/tu-do/boards/boardId/task-card/measured-task-card.tsx +3 -0
- package/src/components/ui/tu-do/boards/boardId/task-card/task-card-comparator.ts +3 -0
- package/src/components/ui/tu-do/boards/boardId/task-card/task-card.tsx +191 -28
- package/src/components/ui/tu-do/boards/boardId/task-filter.test.tsx +152 -0
- package/src/components/ui/tu-do/boards/boardId/task-filter.tsx +555 -545
- package/src/components/ui/tu-do/boards/boardId/task-list.tsx +7 -0
- package/src/components/ui/tu-do/boards/boardId/timeline/timeline-display.ts +9 -0
- package/src/components/ui/tu-do/boards/boardId/timeline/timeline-grid.tsx +8 -16
- package/src/components/ui/tu-do/boards/boardId/timeline/timeline-task-row.tsx +5 -25
- package/src/components/ui/tu-do/boards/boardId/timeline/timeline-utils.test.ts +36 -1
- package/src/components/ui/tu-do/boards/boardId/timeline/timeline-utils.ts +51 -2
- package/src/components/ui/tu-do/boards/share-section.tsx +100 -0
- package/src/components/ui/tu-do/boards/workspace-projects-client-page.tsx +13 -3
- package/src/components/ui/tu-do/drafts/draft-convert-dialog.tsx +10 -12
- package/src/components/ui/tu-do/drafts/drafts-page.tsx +33 -16
- package/src/components/ui/tu-do/initiatives/task-initiatives-client.tsx +56 -88
- package/src/components/ui/tu-do/my-tasks/my-tasks-content.tsx +26 -2
- package/src/components/ui/tu-do/my-tasks/use-my-tasks-state.ts +55 -8
- package/src/components/ui/tu-do/notes/note-edit-dialog.tsx +1 -4
- package/src/components/ui/tu-do/shared/__tests__/board-client.test.tsx +25 -0
- package/src/components/ui/tu-do/shared/__tests__/board-header.test.tsx +341 -38
- package/src/components/ui/tu-do/shared/__tests__/board-switcher.test.tsx +253 -0
- package/src/components/ui/tu-do/shared/__tests__/board-views.test.tsx +237 -3
- package/src/components/ui/tu-do/shared/__tests__/task-board-loading-state.test.tsx +17 -0
- package/src/components/ui/tu-do/shared/__tests__/task-legacy-route-recovery.test.tsx +16 -0
- package/src/components/ui/tu-do/shared/board-client.tsx +2 -7
- package/src/components/ui/tu-do/shared/board-config-storage.ts +7 -1
- package/src/components/ui/tu-do/shared/board-header.tsx +465 -937
- package/src/components/ui/tu-do/shared/board-layout-settings.tsx +165 -136
- package/src/components/ui/tu-do/shared/board-switcher.tsx +209 -217
- package/src/components/ui/tu-do/shared/board-views.tsx +596 -82
- package/src/components/ui/tu-do/shared/cursor-overlay-multi-wrapper.tsx +53 -12
- package/src/components/ui/tu-do/shared/list-view.tsx +227 -1
- package/src/components/ui/tu-do/shared/recycle-bin-panel.tsx +142 -94
- package/src/components/ui/tu-do/shared/special-task-list-pins.ts +51 -0
- package/src/components/ui/tu-do/shared/task-board-loading-state.tsx +28 -0
- package/src/components/ui/tu-do/shared/task-dialog-presentation.test.ts +53 -0
- package/src/components/ui/tu-do/shared/task-dialog-presentation.ts +19 -0
- package/src/components/ui/tu-do/shared/task-edit-dialog/components/compact-task-create-popover.test.tsx +57 -0
- package/src/components/ui/tu-do/shared/task-edit-dialog/components/compact-task-create-popover.tsx +136 -111
- package/src/components/ui/tu-do/shared/task-edit-dialog/components/task-description-editor.tsx +3 -1
- package/src/components/ui/tu-do/shared/task-edit-dialog/field-diff-viewer.tsx +3 -2
- package/src/components/ui/tu-do/shared/task-edit-dialog/selective-revert-panel.test.tsx +91 -0
- package/src/components/ui/tu-do/shared/task-edit-dialog/selective-revert-panel.tsx +123 -78
- package/src/components/ui/tu-do/shared/task-edit-dialog/task-activity-section.tsx +7 -1
- package/src/components/ui/tu-do/shared/task-edit-dialog/task-snapshot-dialog.tsx +8 -3
- package/src/components/ui/tu-do/shared/task-edit-dialog.tsx +44 -15
- package/src/components/ui/tu-do/shared/task-legacy-route-recovery.tsx +2 -9
- package/src/declarations.d.ts +1 -0
- package/src/hooks/__tests__/use-calendar-readonly.test.tsx +322 -2
- package/src/hooks/__tests__/use-calendar-sync.test.tsx +446 -0
- package/src/hooks/__tests__/useBoardRealtime.test.tsx +2 -2
- package/src/hooks/__tests__/useCursorTracking.test.tsx +212 -0
- package/src/hooks/use-calendar-sync.tsx +247 -243
- package/src/hooks/use-calendar.tsx +323 -138
- package/src/hooks/use-task-actions.ts +24 -0
- package/src/hooks/use-user-workspace-config.ts +75 -0
- package/src/hooks/use-workspace-currency.ts +8 -3
- package/src/hooks/useBoardRealtime.ts +6 -3
- package/src/hooks/useBoardRealtime.types.ts +11 -0
- package/src/hooks/useBoardRealtimeEventHandler.ts +11 -0
- package/src/hooks/useCursorTracking.ts +91 -27
- package/src/hooks/useTaskUserRealtime.ts +5 -3
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @vitest-environment jsdom
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { act, render, waitFor } from '@testing-library/react';
|
|
6
|
+
import type { TaskList } from '@tuturuuu/types/primitives/TaskList';
|
|
7
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
8
|
+
import type { ListPaginationState } from '../../shared/progressive-loader-context';
|
|
9
|
+
import { BoardColumn } from './board-column';
|
|
10
|
+
|
|
11
|
+
const mocks = vi.hoisted(() => ({
|
|
12
|
+
createTask: vi.fn(),
|
|
13
|
+
loadListPage: vi.fn(),
|
|
14
|
+
pagination: {} as Record<string, ListPaginationState>,
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
vi.mock('@dnd-kit/sortable', () => ({
|
|
18
|
+
useSortable: () => ({
|
|
19
|
+
attributes: {},
|
|
20
|
+
isDragging: false,
|
|
21
|
+
listeners: {},
|
|
22
|
+
setNodeRef: vi.fn(),
|
|
23
|
+
transform: null,
|
|
24
|
+
transition: null,
|
|
25
|
+
}),
|
|
26
|
+
}));
|
|
27
|
+
|
|
28
|
+
vi.mock('@dnd-kit/utilities', () => ({
|
|
29
|
+
CSS: {
|
|
30
|
+
Transform: {
|
|
31
|
+
toString: () => '',
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
}));
|
|
35
|
+
|
|
36
|
+
vi.mock('next-intl', () => ({
|
|
37
|
+
useTranslations: () => (key: string, values?: Record<string, string>) =>
|
|
38
|
+
values?.name ? `${key}:${values.name}` : key,
|
|
39
|
+
}));
|
|
40
|
+
|
|
41
|
+
vi.mock('../../hooks/useTaskDialog', () => ({
|
|
42
|
+
useTaskDialog: () => ({
|
|
43
|
+
createTask: mocks.createTask,
|
|
44
|
+
}),
|
|
45
|
+
}));
|
|
46
|
+
|
|
47
|
+
vi.mock('../../shared/progressive-loader-context', () => ({
|
|
48
|
+
useProgressiveLoader: () => ({
|
|
49
|
+
loadListPage: mocks.loadListPage,
|
|
50
|
+
pagination: mocks.pagination,
|
|
51
|
+
revalidateLoadedLists: vi.fn(),
|
|
52
|
+
}),
|
|
53
|
+
}));
|
|
54
|
+
|
|
55
|
+
vi.mock('./list-actions', () => ({
|
|
56
|
+
ListActions: () => <div data-testid="list-actions" />,
|
|
57
|
+
}));
|
|
58
|
+
|
|
59
|
+
vi.mock('./task-list', () => ({
|
|
60
|
+
VirtualizedTaskList: () => <div data-testid="task-list" />,
|
|
61
|
+
}));
|
|
62
|
+
|
|
63
|
+
const externalColumn: TaskList = {
|
|
64
|
+
archived: false,
|
|
65
|
+
board_id: 'board-1',
|
|
66
|
+
color: 'CYAN',
|
|
67
|
+
created_at: '2026-06-16T00:00:00.000Z',
|
|
68
|
+
creator_id: 'user-1',
|
|
69
|
+
deleted: false,
|
|
70
|
+
id: 'personal-external-staging:board-1',
|
|
71
|
+
is_external_staging: true,
|
|
72
|
+
name: 'External tasks',
|
|
73
|
+
position: 0,
|
|
74
|
+
status: 'active',
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const loadedExternalState: ListPaginationState = {
|
|
78
|
+
hasMore: true,
|
|
79
|
+
isInitialLoad: false,
|
|
80
|
+
isLoading: false,
|
|
81
|
+
page: 0,
|
|
82
|
+
totalCount: 0,
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
function renderExternalColumn() {
|
|
86
|
+
return (
|
|
87
|
+
<BoardColumn
|
|
88
|
+
boardId="board-1"
|
|
89
|
+
column={externalColumn}
|
|
90
|
+
tasks={[]}
|
|
91
|
+
wsId="personal"
|
|
92
|
+
/>
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
describe('BoardColumn external lane retry behavior', () => {
|
|
97
|
+
beforeEach(() => {
|
|
98
|
+
vi.clearAllMocks();
|
|
99
|
+
mocks.pagination = {
|
|
100
|
+
[externalColumn.id]: loadedExternalState,
|
|
101
|
+
};
|
|
102
|
+
mocks.loadListPage.mockRejectedValue(
|
|
103
|
+
new Error('external lane unavailable')
|
|
104
|
+
);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('does not immediately retry the same failed external-options signature', async () => {
|
|
108
|
+
const { rerender } = render(renderExternalColumn());
|
|
109
|
+
|
|
110
|
+
await waitFor(() => {
|
|
111
|
+
expect(mocks.loadListPage).toHaveBeenCalledTimes(1);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
await act(async () => {
|
|
115
|
+
await Promise.resolve();
|
|
116
|
+
rerender(renderExternalColumn());
|
|
117
|
+
await Promise.resolve();
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
expect(mocks.loadListPage).toHaveBeenCalledTimes(1);
|
|
121
|
+
expect(mocks.loadListPage).toHaveBeenCalledWith(externalColumn.id, 0, {
|
|
122
|
+
externalIncludeDocuments: false,
|
|
123
|
+
externalIncludeDoneClosed: false,
|
|
124
|
+
externalSortBy: 'created-desc',
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
});
|
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
Filter,
|
|
12
12
|
GripVertical,
|
|
13
13
|
Loader2,
|
|
14
|
+
Pin,
|
|
15
|
+
PinOff,
|
|
14
16
|
RotateCcw,
|
|
15
17
|
} from '@tuturuuu/icons';
|
|
16
18
|
import type { ExternalTaskSortBy } from '@tuturuuu/internal-api/tasks';
|
|
@@ -174,6 +176,9 @@ interface BoardColumnProps {
|
|
|
174
176
|
wsId: string;
|
|
175
177
|
onExternalTasksCollapsedChange?: (collapsed: boolean) => void;
|
|
176
178
|
onTaskListCollapsedChange?: (listId: string, collapsed: boolean) => void;
|
|
179
|
+
specialPinned?: boolean;
|
|
180
|
+
onSpecialPinnedChange?: (pinned: boolean) => void;
|
|
181
|
+
readOnly?: boolean;
|
|
177
182
|
}
|
|
178
183
|
|
|
179
184
|
export function BoardColumn({
|
|
@@ -200,6 +205,9 @@ export function BoardColumn({
|
|
|
200
205
|
wsId,
|
|
201
206
|
onExternalTasksCollapsedChange,
|
|
202
207
|
onTaskListCollapsedChange,
|
|
208
|
+
specialPinned = false,
|
|
209
|
+
onSpecialPinnedChange,
|
|
210
|
+
readOnly = false,
|
|
203
211
|
}: BoardColumnProps) {
|
|
204
212
|
const t = useTranslations('common');
|
|
205
213
|
const tTasks = useTranslations('ws-tasks');
|
|
@@ -210,7 +218,9 @@ export function BoardColumn({
|
|
|
210
218
|
const isExternalCollapsed =
|
|
211
219
|
isExternalStaging && column.is_external_collapsed === true;
|
|
212
220
|
const listState = pagination[column.id];
|
|
213
|
-
const isInitialLoad =
|
|
221
|
+
const isInitialLoad = readOnly
|
|
222
|
+
? false
|
|
223
|
+
: !listState || listState.isInitialLoad;
|
|
214
224
|
const [externalIncludeDocuments, setExternalIncludeDocuments] =
|
|
215
225
|
useState(false);
|
|
216
226
|
const [externalIncludeDoneClosed, setExternalIncludeDoneClosed] =
|
|
@@ -259,9 +269,7 @@ export function BoardColumn({
|
|
|
259
269
|
loadedExternalOptionsSignatureRef.current = externalOptionsSignature;
|
|
260
270
|
const promise = loadListPage(column.id, page, externalLoadOptions);
|
|
261
271
|
|
|
262
|
-
promise.catch(() => {
|
|
263
|
-
loadedExternalOptionsSignatureRef.current = null;
|
|
264
|
-
});
|
|
272
|
+
void promise.catch(() => {});
|
|
265
273
|
|
|
266
274
|
return promise;
|
|
267
275
|
},
|
|
@@ -378,7 +386,7 @@ export function BoardColumn({
|
|
|
378
386
|
isDragging,
|
|
379
387
|
} = useSortable({
|
|
380
388
|
id: column.id,
|
|
381
|
-
disabled: isExternalStaging,
|
|
389
|
+
disabled: readOnly || isExternalStaging,
|
|
382
390
|
data: {
|
|
383
391
|
type: 'Column',
|
|
384
392
|
column: {
|
|
@@ -448,6 +456,9 @@ export function BoardColumn({
|
|
|
448
456
|
: visibleTasks.length;
|
|
449
457
|
const externalFilterCount =
|
|
450
458
|
(externalIncludeDocuments ? 1 : 0) + (externalIncludeDoneClosed ? 1 : 0);
|
|
459
|
+
const pinListLabel = specialPinned
|
|
460
|
+
? tTasks('unpin_task_list', { name: translateListName(column.name) })
|
|
461
|
+
: tTasks('pin_task_list', { name: translateListName(column.name) });
|
|
451
462
|
|
|
452
463
|
// Memoize drag handle for performance
|
|
453
464
|
const DragHandle = useMemo(
|
|
@@ -503,6 +514,8 @@ export function BoardColumn({
|
|
|
503
514
|
<Card
|
|
504
515
|
ref={composedRef}
|
|
505
516
|
style={style}
|
|
517
|
+
data-kanban-column-id={column.id}
|
|
518
|
+
data-kanban-real-column={isExternalStaging ? undefined : 'true'}
|
|
506
519
|
className={cn(
|
|
507
520
|
'group flex h-full w-14 shrink-0 snap-start flex-col items-center rounded-xl border border-dashed transition-all duration-200',
|
|
508
521
|
'touch-none select-none overflow-hidden hover:shadow-md',
|
|
@@ -552,6 +565,8 @@ export function BoardColumn({
|
|
|
552
565
|
<Card
|
|
553
566
|
ref={composedRef}
|
|
554
567
|
style={style}
|
|
568
|
+
data-kanban-column-id={column.id}
|
|
569
|
+
data-kanban-real-column={isExternalStaging ? undefined : 'true'}
|
|
555
570
|
className={cn(
|
|
556
571
|
'group flex h-full w-[var(--kanban-column-width)] shrink-0 snap-start flex-col rounded-xl transition-all duration-200 last:snap-end',
|
|
557
572
|
'touch-none select-none',
|
|
@@ -568,7 +583,7 @@ export function BoardColumn({
|
|
|
568
583
|
)}
|
|
569
584
|
>
|
|
570
585
|
<div className="flex items-center gap-2 rounded-t-xl border-b p-3">
|
|
571
|
-
{!isExternalStaging && DragHandle}
|
|
586
|
+
{!readOnly && !isExternalStaging && DragHandle}
|
|
572
587
|
<div className="flex flex-1 items-center gap-2">
|
|
573
588
|
<span className="text-sm">{statusIcon}</span>
|
|
574
589
|
<h3
|
|
@@ -579,9 +594,9 @@ export function BoardColumn({
|
|
|
579
594
|
: 'cursor-pointer hover:underline'
|
|
580
595
|
)}
|
|
581
596
|
onClick={() => {
|
|
582
|
-
if (!isExternalStaging) setIsEditOpen(true);
|
|
597
|
+
if (!readOnly && !isExternalStaging) setIsEditOpen(true);
|
|
583
598
|
}}
|
|
584
|
-
title={isExternalStaging ? undefined : t('edit_list')}
|
|
599
|
+
title={readOnly || isExternalStaging ? undefined : t('edit_list')}
|
|
585
600
|
>
|
|
586
601
|
{translateListName(column.name)}
|
|
587
602
|
</h3>
|
|
@@ -707,53 +722,104 @@ export function BoardColumn({
|
|
|
707
722
|
</DropdownMenuRadioGroup>
|
|
708
723
|
</DropdownMenuContent>
|
|
709
724
|
</DropdownMenu>
|
|
710
|
-
|
|
711
|
-
type="button"
|
|
712
|
-
variant="ghost"
|
|
713
|
-
size="xs"
|
|
714
|
-
className="h-7 w-7 p-0 text-dynamic-cyan hover:bg-dynamic-cyan/10"
|
|
715
|
-
title={tTasks('collapse_external_tasks')}
|
|
716
|
-
aria-label={tTasks('collapse_external_tasks')}
|
|
717
|
-
onClick={() => onExternalTasksCollapsedChange?.(true)}
|
|
718
|
-
>
|
|
719
|
-
<ChevronLeft className="h-3.5 w-3.5" />
|
|
720
|
-
</Button>
|
|
721
|
-
</>
|
|
722
|
-
) : (
|
|
723
|
-
<>
|
|
724
|
-
{isClosedCollapsed || column.status === 'closed' ? (
|
|
725
|
+
{onSpecialPinnedChange ? (
|
|
725
726
|
<Button
|
|
726
727
|
type="button"
|
|
727
728
|
variant="ghost"
|
|
728
729
|
size="xs"
|
|
729
730
|
className={cn(
|
|
730
|
-
'h-7 w-7 p-0 hover:bg-
|
|
731
|
-
|
|
731
|
+
'h-7 w-7 p-0 text-dynamic-cyan hover:bg-dynamic-cyan/10',
|
|
732
|
+
specialPinned && 'bg-dynamic-cyan/10'
|
|
732
733
|
)}
|
|
733
|
-
title={
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
734
|
+
title={pinListLabel}
|
|
735
|
+
aria-label={pinListLabel}
|
|
736
|
+
onClick={() => onSpecialPinnedChange(!specialPinned)}
|
|
737
|
+
>
|
|
738
|
+
{specialPinned ? (
|
|
739
|
+
<PinOff className="h-3.5 w-3.5" />
|
|
740
|
+
) : (
|
|
741
|
+
<Pin className="h-3.5 w-3.5" />
|
|
742
|
+
)}
|
|
743
|
+
</Button>
|
|
744
|
+
) : null}
|
|
745
|
+
{!specialPinned && (
|
|
746
|
+
<Button
|
|
747
|
+
type="button"
|
|
748
|
+
variant="ghost"
|
|
749
|
+
size="xs"
|
|
750
|
+
className="h-7 w-7 p-0 text-dynamic-cyan hover:bg-dynamic-cyan/10"
|
|
751
|
+
title={tTasks('collapse_external_tasks')}
|
|
752
|
+
aria-label={tTasks('collapse_external_tasks')}
|
|
753
|
+
onClick={() => onExternalTasksCollapsedChange?.(true)}
|
|
740
754
|
>
|
|
741
755
|
<ChevronLeft className="h-3.5 w-3.5" />
|
|
742
756
|
</Button>
|
|
757
|
+
)}
|
|
758
|
+
</>
|
|
759
|
+
) : (
|
|
760
|
+
<>
|
|
761
|
+
{isClosedCollapsed || column.status === 'closed' ? (
|
|
762
|
+
<>
|
|
763
|
+
{onSpecialPinnedChange ? (
|
|
764
|
+
<Button
|
|
765
|
+
type="button"
|
|
766
|
+
variant="ghost"
|
|
767
|
+
size="xs"
|
|
768
|
+
className={cn(
|
|
769
|
+
'h-7 w-7 p-0 hover:bg-muted/40',
|
|
770
|
+
getListTextColorClass(column.color as SupportedColor),
|
|
771
|
+
specialPinned && 'bg-muted/40'
|
|
772
|
+
)}
|
|
773
|
+
title={pinListLabel}
|
|
774
|
+
aria-label={pinListLabel}
|
|
775
|
+
onClick={() => onSpecialPinnedChange(!specialPinned)}
|
|
776
|
+
>
|
|
777
|
+
{specialPinned ? (
|
|
778
|
+
<PinOff className="h-3.5 w-3.5" />
|
|
779
|
+
) : (
|
|
780
|
+
<Pin className="h-3.5 w-3.5" />
|
|
781
|
+
)}
|
|
782
|
+
</Button>
|
|
783
|
+
) : null}
|
|
784
|
+
{!specialPinned && (
|
|
785
|
+
<Button
|
|
786
|
+
type="button"
|
|
787
|
+
variant="ghost"
|
|
788
|
+
size="xs"
|
|
789
|
+
className={cn(
|
|
790
|
+
'h-7 w-7 p-0 hover:bg-muted/40',
|
|
791
|
+
getListTextColorClass(column.color as SupportedColor)
|
|
792
|
+
)}
|
|
793
|
+
title={tTasks('collapse_task_list', {
|
|
794
|
+
name: translateListName(column.name),
|
|
795
|
+
})}
|
|
796
|
+
aria-label={tTasks('collapse_task_list', {
|
|
797
|
+
name: translateListName(column.name),
|
|
798
|
+
})}
|
|
799
|
+
onClick={() =>
|
|
800
|
+
onTaskListCollapsedChange?.(column.id, true)
|
|
801
|
+
}
|
|
802
|
+
>
|
|
803
|
+
<ChevronLeft className="h-3.5 w-3.5" />
|
|
804
|
+
</Button>
|
|
805
|
+
)}
|
|
806
|
+
</>
|
|
743
807
|
) : null}
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
808
|
+
{!readOnly && (
|
|
809
|
+
<ListActions
|
|
810
|
+
listId={column.id}
|
|
811
|
+
listName={column.name}
|
|
812
|
+
listStatus={column.status}
|
|
813
|
+
listColor={column.color as SupportedColor}
|
|
814
|
+
tasks={tasks}
|
|
815
|
+
boardId={boardId}
|
|
816
|
+
wsId={wsId}
|
|
817
|
+
onUpdate={handleUpdate}
|
|
818
|
+
onSelectAll={handleSelectAll}
|
|
819
|
+
isEditOpen={isEditOpen}
|
|
820
|
+
onEditOpenChange={setIsEditOpen}
|
|
821
|
+
/>
|
|
822
|
+
)}
|
|
757
823
|
</>
|
|
758
824
|
)}
|
|
759
825
|
</div>
|
|
@@ -785,10 +851,11 @@ export function BoardColumn({
|
|
|
785
851
|
onLoadMore={handleLoadMore}
|
|
786
852
|
hasMore={listState?.hasMore ?? false}
|
|
787
853
|
isLoadingMore={listState?.isLoading ?? false}
|
|
854
|
+
readOnly={readOnly}
|
|
788
855
|
/>
|
|
789
856
|
)}
|
|
790
857
|
|
|
791
|
-
{!isExternalStaging && (
|
|
858
|
+
{!readOnly && !isExternalStaging && (
|
|
792
859
|
<div className="rounded-b-xl border-t p-3 backdrop-blur-sm">
|
|
793
860
|
<Button
|
|
794
861
|
variant="ghost"
|
|
@@ -4,6 +4,7 @@ import { type QueryClient, useMutation } from '@tanstack/react-query';
|
|
|
4
4
|
import { bulkWorkspaceTasks } from '@tuturuuu/internal-api/tasks';
|
|
5
5
|
import { toast } from '@tuturuuu/ui/sonner';
|
|
6
6
|
import type { BoardBroadcastFn } from '../../../../shared/board-broadcast-context';
|
|
7
|
+
import { invalidateKanbanDeadlineTasks } from '../data/kanban-deadline-query';
|
|
7
8
|
import type { BulkOperationI18n } from './bulk-operation-i18n';
|
|
8
9
|
import {
|
|
9
10
|
type BulkTaskWorkspaceGroup,
|
|
@@ -390,6 +391,7 @@ export function useBulkDeleteTasks(
|
|
|
390
391
|
for (const tid of succeededTaskIds) {
|
|
391
392
|
broadcast?.('task:delete', { taskId: tid });
|
|
392
393
|
}
|
|
394
|
+
void invalidateKanbanDeadlineTasks(queryClient, boardId);
|
|
393
395
|
|
|
394
396
|
clearSelection();
|
|
395
397
|
setBulkDeleteOpen(false);
|
|
@@ -6,6 +6,7 @@ import type { Task } from '@tuturuuu/types/primitives/Task';
|
|
|
6
6
|
import type { TaskList } from '@tuturuuu/types/primitives/TaskList';
|
|
7
7
|
import { toast } from '@tuturuuu/ui/sonner';
|
|
8
8
|
import type { BoardBroadcastFn } from '../../../../shared/board-broadcast-context';
|
|
9
|
+
import { invalidateKanbanDeadlineTasks } from '../data/kanban-deadline-query';
|
|
9
10
|
import type { BulkOperationI18n } from './bulk-operation-i18n';
|
|
10
11
|
import { getInternalApiOptions } from './bulk-operation-utils';
|
|
11
12
|
import {
|
|
@@ -184,6 +185,8 @@ export function useBulkMoveToBoard(
|
|
|
184
185
|
for (const tid of movedTaskIds) {
|
|
185
186
|
broadcast?.('task:delete', { taskId: tid });
|
|
186
187
|
}
|
|
188
|
+
void invalidateKanbanDeadlineTasks(queryClient, boardId);
|
|
189
|
+
void invalidateKanbanDeadlineTasks(queryClient, data.targetBoardId);
|
|
187
190
|
|
|
188
191
|
if (data.failures.length > 0) {
|
|
189
192
|
toast.warning(
|
|
@@ -428,6 +431,7 @@ export function useBulkMoveToList(
|
|
|
428
431
|
},
|
|
429
432
|
});
|
|
430
433
|
}
|
|
434
|
+
void invalidateKanbanDeadlineTasks(queryClient, boardId);
|
|
431
435
|
|
|
432
436
|
if (data.failures.length > 0) {
|
|
433
437
|
toast.warning(
|
|
@@ -631,6 +635,7 @@ export function useBulkMoveToStatus(
|
|
|
631
635
|
},
|
|
632
636
|
});
|
|
633
637
|
}
|
|
638
|
+
void invalidateKanbanDeadlineTasks(queryClient, boardId);
|
|
634
639
|
|
|
635
640
|
if (data.failures.length > 0) {
|
|
636
641
|
toast.warning(
|
|
@@ -4,6 +4,7 @@ import { type QueryClient, useMutation } from '@tanstack/react-query';
|
|
|
4
4
|
import type { Task } from '@tuturuuu/types/primitives/Task';
|
|
5
5
|
import { toast } from '@tuturuuu/ui/sonner';
|
|
6
6
|
import type { BoardBroadcastFn } from '../../../../shared/board-broadcast-context';
|
|
7
|
+
import { invalidateKanbanDeadlineTasks } from '../data/kanban-deadline-query';
|
|
7
8
|
import type { BulkOperationI18n } from './bulk-operation-i18n';
|
|
8
9
|
import {
|
|
9
10
|
bulkWorkspaceTasksByEffectiveWorkspace,
|
|
@@ -322,6 +323,7 @@ export function useBulkUpdateDueDate(
|
|
|
322
323
|
task: { id: tid, end_date: data.end_date },
|
|
323
324
|
});
|
|
324
325
|
}
|
|
326
|
+
void invalidateKanbanDeadlineTasks(queryClient, boardId);
|
|
325
327
|
|
|
326
328
|
if (data.failures.length > 0) {
|
|
327
329
|
toast.warning(
|
|
@@ -434,6 +436,7 @@ export function useBulkUpdateCustomDueDate(
|
|
|
434
436
|
task: { id: tid, end_date: data.end_date },
|
|
435
437
|
});
|
|
436
438
|
}
|
|
439
|
+
void invalidateKanbanDeadlineTasks(queryClient, boardId);
|
|
437
440
|
|
|
438
441
|
if (data.failures.length > 0) {
|
|
439
442
|
toast.warning(
|
|
@@ -1,22 +1,70 @@
|
|
|
1
|
+
import type { QueryClient } from '@tanstack/react-query';
|
|
1
2
|
import { listWorkspaceTasks } from '@tuturuuu/internal-api';
|
|
3
|
+
import type { ListWorkspaceTasksOptions } from '@tuturuuu/internal-api/tasks';
|
|
2
4
|
import type { Task } from '@tuturuuu/types/primitives/Task';
|
|
3
5
|
|
|
4
6
|
const KANBAN_DEADLINE_TASK_PAGE_SIZE = 200;
|
|
7
|
+
export const KANBAN_DEADLINE_TASKS_QUERY_KEY = 'kanban-deadline-tasks';
|
|
8
|
+
|
|
9
|
+
export function getKanbanDeadlineTasksQueryKey(
|
|
10
|
+
workspaceId: string,
|
|
11
|
+
boardId: string | null | undefined,
|
|
12
|
+
taskQueryOptions?: ListWorkspaceTasksOptions
|
|
13
|
+
) {
|
|
14
|
+
return [
|
|
15
|
+
KANBAN_DEADLINE_TASKS_QUERY_KEY,
|
|
16
|
+
workspaceId,
|
|
17
|
+
boardId,
|
|
18
|
+
taskQueryOptions,
|
|
19
|
+
] as const;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function invalidateKanbanDeadlineTasks(
|
|
23
|
+
queryClient: QueryClient,
|
|
24
|
+
boardId?: string | null
|
|
25
|
+
) {
|
|
26
|
+
return queryClient.invalidateQueries({
|
|
27
|
+
predicate: (query) => {
|
|
28
|
+
const queryKey = query.queryKey;
|
|
29
|
+
if (!Array.isArray(queryKey)) return false;
|
|
30
|
+
if (queryKey[0] !== KANBAN_DEADLINE_TASKS_QUERY_KEY) return false;
|
|
31
|
+
return !boardId || queryKey[2] === boardId;
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
}
|
|
5
35
|
|
|
6
36
|
interface ListKanbanDeadlineTasksOptions {
|
|
7
37
|
boardId: string;
|
|
38
|
+
taskQueryOptions?: ListWorkspaceTasksOptions;
|
|
8
39
|
workspaceId: string;
|
|
9
40
|
}
|
|
10
41
|
|
|
11
42
|
export async function listKanbanDeadlineTasks({
|
|
12
43
|
boardId,
|
|
44
|
+
taskQueryOptions,
|
|
13
45
|
workspaceId,
|
|
14
46
|
}: ListKanbanDeadlineTasksOptions): Promise<Task[]> {
|
|
15
47
|
const tasks: Task[] = [];
|
|
16
48
|
let offset = 0;
|
|
49
|
+
const {
|
|
50
|
+
boardId: _boardId,
|
|
51
|
+
closed: _closed,
|
|
52
|
+
completed: _completed,
|
|
53
|
+
externalSortBy: _externalSortBy,
|
|
54
|
+
hasDueDate: _hasDueDate,
|
|
55
|
+
includeCount: _includeCount,
|
|
56
|
+
includeListCounts: _includeListCounts,
|
|
57
|
+
includeRelationshipSummary: _includeRelationshipSummary,
|
|
58
|
+
limit: _limit,
|
|
59
|
+
listId: _listId,
|
|
60
|
+
offset: _offset,
|
|
61
|
+
sortBy: _sortBy,
|
|
62
|
+
...filterOptions
|
|
63
|
+
} = taskQueryOptions ?? {};
|
|
17
64
|
|
|
18
65
|
while (true) {
|
|
19
66
|
const response = await listWorkspaceTasks(workspaceId, {
|
|
67
|
+
...filterOptions,
|
|
20
68
|
boardId,
|
|
21
69
|
closed: 'exclude',
|
|
22
70
|
completed: 'exclude',
|
|
@@ -25,9 +73,9 @@ export async function listKanbanDeadlineTasks({
|
|
|
25
73
|
includeCount: true,
|
|
26
74
|
includeRelationshipSummary: false,
|
|
27
75
|
limit: KANBAN_DEADLINE_TASK_PAGE_SIZE,
|
|
28
|
-
listStatuses: ['not_started', 'active'],
|
|
76
|
+
listStatuses: filterOptions.listStatuses ?? ['not_started', 'active'],
|
|
29
77
|
offset,
|
|
30
|
-
sourceScope: 'all_visible',
|
|
78
|
+
sourceScope: filterOptions.sourceScope ?? 'all_visible',
|
|
31
79
|
});
|
|
32
80
|
|
|
33
81
|
tasks.push(...response.tasks);
|
|
@@ -43,6 +43,23 @@ describe('getColumnReorderUpdates', () => {
|
|
|
43
43
|
expect(getColumnReorderUpdates(columns, 'todo', 'doing')).toBeNull();
|
|
44
44
|
});
|
|
45
45
|
|
|
46
|
+
it('excludes synthetic external staging lanes from persisted position repairs', () => {
|
|
47
|
+
const externalLane = {
|
|
48
|
+
...makeList('external', 'not_started', -1),
|
|
49
|
+
is_external_staging: true,
|
|
50
|
+
};
|
|
51
|
+
const columns = [
|
|
52
|
+
externalLane,
|
|
53
|
+
makeList('todo', 'not_started', 0),
|
|
54
|
+
makeList('backlog', 'not_started', 1),
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
expect(getColumnReorderUpdates(columns, 'backlog', 'todo')).toEqual([
|
|
58
|
+
{ listId: 'backlog', newPosition: 0 },
|
|
59
|
+
{ listId: 'todo', newPosition: 1 },
|
|
60
|
+
]);
|
|
61
|
+
});
|
|
62
|
+
|
|
46
63
|
it('sorts columns in the same order they are rendered in Kanban', () => {
|
|
47
64
|
const columns = [
|
|
48
65
|
makeList('closed', 'closed', 0),
|
|
@@ -39,7 +39,10 @@ export function getColumnReorderUpdates(
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
const statusColumns = [...columns]
|
|
42
|
-
.filter(
|
|
42
|
+
.filter(
|
|
43
|
+
(column) =>
|
|
44
|
+
column.status === activeColumn.status && !column.is_external_staging
|
|
45
|
+
)
|
|
43
46
|
.sort((a, b) => (a.position ?? 0) - (b.position ?? 0));
|
|
44
47
|
|
|
45
48
|
const activeIndex = statusColumns.findIndex(
|