@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,51 @@
|
|
|
1
|
+
export type SpecialTaskListPin =
|
|
2
|
+
| 'closed_tasks'
|
|
3
|
+
| 'external_tasks'
|
|
4
|
+
| 'overdue'
|
|
5
|
+
| 'upcoming';
|
|
6
|
+
|
|
7
|
+
export const SPECIAL_TASK_LIST_PIN_VALUES: readonly SpecialTaskListPin[] = [
|
|
8
|
+
'overdue',
|
|
9
|
+
'upcoming',
|
|
10
|
+
'external_tasks',
|
|
11
|
+
'closed_tasks',
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
const SPECIAL_TASK_LIST_PIN_SET = new Set<string>(SPECIAL_TASK_LIST_PIN_VALUES);
|
|
15
|
+
|
|
16
|
+
export type SpecialTaskListPinState = Partial<
|
|
17
|
+
Record<SpecialTaskListPin, boolean>
|
|
18
|
+
>;
|
|
19
|
+
|
|
20
|
+
export function parseSpecialTaskListPins(
|
|
21
|
+
raw: string | null | undefined
|
|
22
|
+
): SpecialTaskListPinState {
|
|
23
|
+
if (!raw) return {};
|
|
24
|
+
|
|
25
|
+
const parseValues = (value: unknown) => {
|
|
26
|
+
if (!Array.isArray(value)) return [];
|
|
27
|
+
return value.filter((item): item is SpecialTaskListPin => {
|
|
28
|
+
return typeof item === 'string' && SPECIAL_TASK_LIST_PIN_SET.has(item);
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
let values: SpecialTaskListPin[] = [];
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
values = parseValues(JSON.parse(raw));
|
|
36
|
+
} catch {
|
|
37
|
+
values = parseValues(raw.split(',').map((item) => item.trim()));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return values.reduce<SpecialTaskListPinState>((acc, pin) => {
|
|
41
|
+
acc[pin] = true;
|
|
42
|
+
return acc;
|
|
43
|
+
}, {});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function serializeSpecialTaskListPins(
|
|
47
|
+
state: SpecialTaskListPinState
|
|
48
|
+
): string | null {
|
|
49
|
+
const pins = SPECIAL_TASK_LIST_PIN_VALUES.filter((pin) => state[pin]);
|
|
50
|
+
return pins.length > 0 ? JSON.stringify(pins) : null;
|
|
51
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { cn } from '@tuturuuu/utils/format';
|
|
4
|
+
import { KanbanSkeleton } from '../boards/boardId/kanban/rendering/kanban-skeleton';
|
|
5
|
+
|
|
6
|
+
export function TaskBoardLoadingState({
|
|
7
|
+
className,
|
|
8
|
+
root = false,
|
|
9
|
+
}: {
|
|
10
|
+
className?: string;
|
|
11
|
+
root?: boolean;
|
|
12
|
+
}) {
|
|
13
|
+
return (
|
|
14
|
+
<div
|
|
15
|
+
aria-busy="true"
|
|
16
|
+
className={cn(
|
|
17
|
+
'w-full overflow-hidden bg-transparent',
|
|
18
|
+
root
|
|
19
|
+
? '-m-4 h-[calc(100dvh+2rem)] min-h-[calc(32rem+2rem)]'
|
|
20
|
+
: 'h-[calc(100dvh-1rem)] min-h-[32rem]',
|
|
21
|
+
className
|
|
22
|
+
)}
|
|
23
|
+
data-testid="task-board-loading-state"
|
|
24
|
+
>
|
|
25
|
+
<KanbanSkeleton />
|
|
26
|
+
</div>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { resolveTaskDialogOpeningPresentation } from './task-dialog-presentation';
|
|
3
|
+
|
|
4
|
+
describe('resolveTaskDialogOpeningPresentation', () => {
|
|
5
|
+
it('opens existing document-list tasks fullscreen', () => {
|
|
6
|
+
expect(
|
|
7
|
+
resolveTaskDialogOpeningPresentation({
|
|
8
|
+
defaultPresentation: 'compact',
|
|
9
|
+
mode: 'edit',
|
|
10
|
+
selectedListStatus: 'documents',
|
|
11
|
+
})
|
|
12
|
+
).toBe('fullscreen');
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('keeps create mode compact even in document lists', () => {
|
|
16
|
+
expect(
|
|
17
|
+
resolveTaskDialogOpeningPresentation({
|
|
18
|
+
defaultPresentation: 'fullscreen',
|
|
19
|
+
mode: 'create',
|
|
20
|
+
selectedListStatus: 'documents',
|
|
21
|
+
})
|
|
22
|
+
).toBe('compact');
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('respects the user default for existing non-document tasks', () => {
|
|
26
|
+
expect(
|
|
27
|
+
resolveTaskDialogOpeningPresentation({
|
|
28
|
+
defaultPresentation: 'compact',
|
|
29
|
+
mode: 'edit',
|
|
30
|
+
selectedListStatus: 'active',
|
|
31
|
+
})
|
|
32
|
+
).toBe('compact');
|
|
33
|
+
|
|
34
|
+
expect(
|
|
35
|
+
resolveTaskDialogOpeningPresentation({
|
|
36
|
+
defaultPresentation: 'fullscreen',
|
|
37
|
+
mode: 'edit',
|
|
38
|
+
selectedListStatus: 'not_started',
|
|
39
|
+
})
|
|
40
|
+
).toBe('fullscreen');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('keeps drafts fullscreen', () => {
|
|
44
|
+
expect(
|
|
45
|
+
resolveTaskDialogOpeningPresentation({
|
|
46
|
+
defaultPresentation: 'compact',
|
|
47
|
+
draftId: 'draft-1',
|
|
48
|
+
mode: 'create',
|
|
49
|
+
selectedListStatus: 'documents',
|
|
50
|
+
})
|
|
51
|
+
).toBe('fullscreen');
|
|
52
|
+
});
|
|
53
|
+
});
|
|
@@ -2,6 +2,7 @@ export const TASK_DIALOG_DEFAULT_PRESENTATION_CONFIG_ID =
|
|
|
2
2
|
'TASK_DIALOG_DEFAULT_PRESENTATION';
|
|
3
3
|
|
|
4
4
|
export type TaskDialogPresentation = 'compact' | 'fullscreen';
|
|
5
|
+
export type TaskDialogMode = 'edit' | 'create';
|
|
5
6
|
|
|
6
7
|
export function normalizeTaskDialogPresentation(
|
|
7
8
|
value: unknown,
|
|
@@ -9,3 +10,21 @@ export function normalizeTaskDialogPresentation(
|
|
|
9
10
|
): TaskDialogPresentation {
|
|
10
11
|
return value === 'fullscreen' || value === 'compact' ? value : fallback;
|
|
11
12
|
}
|
|
13
|
+
|
|
14
|
+
export function resolveTaskDialogOpeningPresentation({
|
|
15
|
+
defaultPresentation,
|
|
16
|
+
draftId,
|
|
17
|
+
mode = 'edit',
|
|
18
|
+
selectedListStatus,
|
|
19
|
+
}: {
|
|
20
|
+
defaultPresentation?: unknown;
|
|
21
|
+
draftId?: string;
|
|
22
|
+
mode?: TaskDialogMode;
|
|
23
|
+
selectedListStatus?: string | null;
|
|
24
|
+
}): TaskDialogPresentation {
|
|
25
|
+
if (draftId) return 'fullscreen';
|
|
26
|
+
if (mode === 'create') return 'compact';
|
|
27
|
+
if (selectedListStatus === 'documents') return 'fullscreen';
|
|
28
|
+
|
|
29
|
+
return normalizeTaskDialogPresentation(defaultPresentation);
|
|
30
|
+
}
|
|
@@ -178,6 +178,63 @@ describe('CompactTaskCreatePopover', () => {
|
|
|
178
178
|
).not.toBeInTheDocument();
|
|
179
179
|
});
|
|
180
180
|
|
|
181
|
+
it('renders compact description preview without affecting panel layout', () => {
|
|
182
|
+
const onDescriptionPreviewClick = vi.fn();
|
|
183
|
+
|
|
184
|
+
render(
|
|
185
|
+
<Dialog open={true}>
|
|
186
|
+
<CompactTaskCreatePopover
|
|
187
|
+
title="Edit task"
|
|
188
|
+
titleInput={<input aria-label="Task title" defaultValue="Existing" />}
|
|
189
|
+
propertyControls={
|
|
190
|
+
<button type="button" aria-label="List: Inbox">
|
|
191
|
+
List
|
|
192
|
+
</button>
|
|
193
|
+
}
|
|
194
|
+
descriptionPreview="Confirm the plan and publish the final notes."
|
|
195
|
+
descriptionPreviewLabel="Open full task"
|
|
196
|
+
onDescriptionPreviewClick={onDescriptionPreviewClick}
|
|
197
|
+
onClose={vi.fn()}
|
|
198
|
+
onFullscreen={vi.fn()}
|
|
199
|
+
/>
|
|
200
|
+
</Dialog>
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
const preview = screen.getByTestId('compact-task-description-preview');
|
|
204
|
+
|
|
205
|
+
expect(preview).toHaveTextContent(
|
|
206
|
+
'Confirm the plan and publish the final notes.'
|
|
207
|
+
);
|
|
208
|
+
expect(preview).toHaveAttribute('aria-label', 'Open full task');
|
|
209
|
+
expect(preview).toHaveClass('absolute', 'top-full');
|
|
210
|
+
|
|
211
|
+
fireEvent.click(preview);
|
|
212
|
+
|
|
213
|
+
expect(onDescriptionPreviewClick).toHaveBeenCalledTimes(1);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it('omits compact description preview when the caller does not provide one', () => {
|
|
217
|
+
render(
|
|
218
|
+
<Dialog open={true}>
|
|
219
|
+
<CompactTaskCreatePopover
|
|
220
|
+
title="Create task"
|
|
221
|
+
titleInput={<input aria-label="Task title" defaultValue="New" />}
|
|
222
|
+
propertyControls={
|
|
223
|
+
<button type="button" aria-label="List: Inbox">
|
|
224
|
+
List
|
|
225
|
+
</button>
|
|
226
|
+
}
|
|
227
|
+
onClose={vi.fn()}
|
|
228
|
+
onFullscreen={vi.fn()}
|
|
229
|
+
/>
|
|
230
|
+
</Dialog>
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
expect(
|
|
234
|
+
screen.queryByTestId('compact-task-description-preview')
|
|
235
|
+
).not.toBeInTheDocument();
|
|
236
|
+
});
|
|
237
|
+
|
|
181
238
|
it('renders compact edit actions when provided', () => {
|
|
182
239
|
const onDelete = vi.fn();
|
|
183
240
|
const onDone = vi.fn();
|
package/src/components/ui/tu-do/shared/task-edit-dialog/components/compact-task-create-popover.tsx
CHANGED
|
@@ -25,6 +25,8 @@ interface CompactTaskDialogPanelProps {
|
|
|
25
25
|
iconRingClass?: string;
|
|
26
26
|
titleInput: ReactNode;
|
|
27
27
|
showHeaderTitle?: boolean;
|
|
28
|
+
descriptionPreview?: string | null;
|
|
29
|
+
descriptionPreviewLabel?: string;
|
|
28
30
|
taskStatus?: ReactNode;
|
|
29
31
|
propertyControls: ReactNode;
|
|
30
32
|
editActions?: ReactNode;
|
|
@@ -39,6 +41,7 @@ interface CompactTaskDialogPanelProps {
|
|
|
39
41
|
onCreateMultipleChange?: (value: boolean) => void;
|
|
40
42
|
onClose: () => void;
|
|
41
43
|
onFullscreen: () => void;
|
|
44
|
+
onDescriptionPreviewClick?: () => void;
|
|
42
45
|
onSave?: () => void;
|
|
43
46
|
}
|
|
44
47
|
|
|
@@ -84,6 +87,8 @@ export function CompactTaskDialogPanel({
|
|
|
84
87
|
iconRingClass = 'ring-dynamic-orange/20',
|
|
85
88
|
titleInput,
|
|
86
89
|
showHeaderTitle = true,
|
|
90
|
+
descriptionPreview,
|
|
91
|
+
descriptionPreviewLabel,
|
|
87
92
|
taskStatus,
|
|
88
93
|
propertyControls,
|
|
89
94
|
editActions,
|
|
@@ -98,6 +103,7 @@ export function CompactTaskDialogPanel({
|
|
|
98
103
|
onCreateMultipleChange,
|
|
99
104
|
onClose,
|
|
100
105
|
onFullscreen,
|
|
106
|
+
onDescriptionPreviewClick,
|
|
101
107
|
onSave,
|
|
102
108
|
}: CompactTaskDialogPanelProps) {
|
|
103
109
|
const t = useTranslations();
|
|
@@ -114,127 +120,146 @@ export function CompactTaskDialogPanel({
|
|
|
114
120
|
const hasHeaderTitle = showHeaderTitle;
|
|
115
121
|
|
|
116
122
|
return (
|
|
117
|
-
<div
|
|
118
|
-
data-testid="compact-task-dialog-panel"
|
|
119
|
-
className="flex max-h-[calc(100vh-2rem)] min-h-0 flex-col overflow-hidden rounded-lg bg-background"
|
|
120
|
-
>
|
|
123
|
+
<div className="relative">
|
|
121
124
|
<div
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
hasHeaderTitle ? 'justify-between' : 'justify-end'
|
|
125
|
-
)}
|
|
125
|
+
data-testid="compact-task-dialog-panel"
|
|
126
|
+
className="flex max-h-[calc(100vh-2rem)] min-h-0 flex-col overflow-hidden rounded-lg bg-background"
|
|
126
127
|
>
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
128
|
+
<div
|
|
129
|
+
className={cn(
|
|
130
|
+
'flex items-start gap-3 border-b px-4 py-3',
|
|
131
|
+
hasHeaderTitle ? 'justify-between' : 'justify-end'
|
|
132
|
+
)}
|
|
133
|
+
>
|
|
134
|
+
{hasHeaderTitle ? (
|
|
135
|
+
<div className="flex min-w-0 items-start gap-2.5">
|
|
136
|
+
<div
|
|
137
|
+
className={cn(
|
|
138
|
+
'mt-0.5 flex h-8 w-8 shrink-0 items-center justify-center rounded-lg ring-1',
|
|
139
|
+
iconBgClass,
|
|
140
|
+
iconRingClass
|
|
141
|
+
)}
|
|
142
|
+
>
|
|
143
|
+
{icon ?? <ListTodo className="h-4 w-4 text-dynamic-orange" />}
|
|
144
|
+
</div>
|
|
145
|
+
<div className="min-w-0 space-y-0.5">
|
|
146
|
+
<DialogTitle className="truncate font-semibold text-base">
|
|
147
|
+
{title}
|
|
148
|
+
</DialogTitle>
|
|
149
|
+
{description && (
|
|
150
|
+
<DialogDescription className="truncate text-muted-foreground text-xs">
|
|
151
|
+
{description}
|
|
152
|
+
</DialogDescription>
|
|
153
|
+
)}
|
|
154
|
+
</div>
|
|
147
155
|
</div>
|
|
156
|
+
) : (
|
|
157
|
+
<DialogTitle className="sr-only">{title}</DialogTitle>
|
|
158
|
+
)}
|
|
159
|
+
<div className="flex shrink-0 items-center gap-1">
|
|
160
|
+
{smartAction}
|
|
161
|
+
{editActions}
|
|
162
|
+
<Tooltip>
|
|
163
|
+
<TooltipTrigger asChild>
|
|
164
|
+
<Button
|
|
165
|
+
type="button"
|
|
166
|
+
variant="ghost"
|
|
167
|
+
size="icon"
|
|
168
|
+
aria-label={t('ws-task-boards.dialog.open_fullscreen')}
|
|
169
|
+
className="h-8 w-8 text-muted-foreground hover:text-foreground"
|
|
170
|
+
onClick={onFullscreen}
|
|
171
|
+
>
|
|
172
|
+
<Maximize2 className="h-4 w-4" />
|
|
173
|
+
</Button>
|
|
174
|
+
</TooltipTrigger>
|
|
175
|
+
<TooltipContent side="bottom">
|
|
176
|
+
{t('ws-task-boards.dialog.open_fullscreen')}
|
|
177
|
+
</TooltipContent>
|
|
178
|
+
</Tooltip>
|
|
179
|
+
<Tooltip>
|
|
180
|
+
<TooltipTrigger asChild>
|
|
181
|
+
<Button
|
|
182
|
+
type="button"
|
|
183
|
+
variant="ghost"
|
|
184
|
+
size="icon"
|
|
185
|
+
aria-label={t('common.close')}
|
|
186
|
+
className="h-8 w-8 text-muted-foreground hover:text-foreground"
|
|
187
|
+
onClick={onClose}
|
|
188
|
+
>
|
|
189
|
+
<X className="h-4 w-4" />
|
|
190
|
+
</Button>
|
|
191
|
+
</TooltipTrigger>
|
|
192
|
+
<TooltipContent side="bottom">{t('common.close')}</TooltipContent>
|
|
193
|
+
</Tooltip>
|
|
148
194
|
</div>
|
|
149
|
-
) : (
|
|
150
|
-
<DialogTitle className="sr-only">{title}</DialogTitle>
|
|
151
|
-
)}
|
|
152
|
-
<div className="flex shrink-0 items-center gap-1">
|
|
153
|
-
{smartAction}
|
|
154
|
-
{editActions}
|
|
155
|
-
<Tooltip>
|
|
156
|
-
<TooltipTrigger asChild>
|
|
157
|
-
<Button
|
|
158
|
-
type="button"
|
|
159
|
-
variant="ghost"
|
|
160
|
-
size="icon"
|
|
161
|
-
aria-label={t('ws-task-boards.dialog.open_fullscreen')}
|
|
162
|
-
className="h-8 w-8 text-muted-foreground hover:text-foreground"
|
|
163
|
-
onClick={onFullscreen}
|
|
164
|
-
>
|
|
165
|
-
<Maximize2 className="h-4 w-4" />
|
|
166
|
-
</Button>
|
|
167
|
-
</TooltipTrigger>
|
|
168
|
-
<TooltipContent side="bottom">
|
|
169
|
-
{t('ws-task-boards.dialog.open_fullscreen')}
|
|
170
|
-
</TooltipContent>
|
|
171
|
-
</Tooltip>
|
|
172
|
-
<Tooltip>
|
|
173
|
-
<TooltipTrigger asChild>
|
|
174
|
-
<Button
|
|
175
|
-
type="button"
|
|
176
|
-
variant="ghost"
|
|
177
|
-
size="icon"
|
|
178
|
-
aria-label={t('common.close')}
|
|
179
|
-
className="h-8 w-8 text-muted-foreground hover:text-foreground"
|
|
180
|
-
onClick={onClose}
|
|
181
|
-
>
|
|
182
|
-
<X className="h-4 w-4" />
|
|
183
|
-
</Button>
|
|
184
|
-
</TooltipTrigger>
|
|
185
|
-
<TooltipContent side="bottom">{t('common.close')}</TooltipContent>
|
|
186
|
-
</Tooltip>
|
|
187
195
|
</div>
|
|
188
|
-
</div>
|
|
189
196
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
197
|
+
<div className="min-h-0 space-y-3 overflow-y-auto px-4 py-3">
|
|
198
|
+
{titleInput}
|
|
199
|
+
{taskStatus}
|
|
200
|
+
<div className="flex flex-wrap items-center gap-1.5">
|
|
201
|
+
{propertyControls}
|
|
202
|
+
</div>
|
|
203
|
+
{smartPanel}
|
|
195
204
|
</div>
|
|
196
|
-
{smartPanel}
|
|
197
|
-
</div>
|
|
198
205
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
206
|
+
{hasCreateActions && (
|
|
207
|
+
<div className="flex items-center justify-between gap-2 border-t bg-muted/20 px-4 py-3">
|
|
208
|
+
<div className="flex items-center gap-1">
|
|
209
|
+
<CompactIconButton
|
|
210
|
+
active={!!saveAsDraft}
|
|
211
|
+
label={t('task-drafts.save_as_draft')}
|
|
212
|
+
onClick={() => onSaveAsDraftChange?.(!saveAsDraft)}
|
|
213
|
+
>
|
|
214
|
+
<FileEdit className="h-4 w-4" />
|
|
215
|
+
</CompactIconButton>
|
|
216
|
+
<CompactIconButton
|
|
217
|
+
active={!!createMultiple}
|
|
218
|
+
label={t('ws-task-boards.dialog.create_multiple')}
|
|
219
|
+
onClick={() => onCreateMultipleChange?.(!createMultiple)}
|
|
220
|
+
>
|
|
221
|
+
<Copy className="h-4 w-4" />
|
|
222
|
+
</CompactIconButton>
|
|
223
|
+
<QuickSettingsPopover isPersonalWorkspace={isPersonalWorkspace} />
|
|
224
|
+
</div>
|
|
225
|
+
<Button
|
|
226
|
+
type="button"
|
|
227
|
+
size="sm"
|
|
228
|
+
disabled={!canSave}
|
|
229
|
+
onClick={() => onSave?.()}
|
|
230
|
+
className="min-w-28"
|
|
213
231
|
>
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
232
|
+
{isLoading ? (
|
|
233
|
+
<>
|
|
234
|
+
<Loader2 className="h-4 w-4 animate-spin" />
|
|
235
|
+
{t('ws-task-boards.dialog.saving')}
|
|
236
|
+
</>
|
|
237
|
+
) : (
|
|
238
|
+
<>
|
|
239
|
+
<Check className="h-4 w-4" />
|
|
240
|
+
{saveLabel}
|
|
241
|
+
</>
|
|
242
|
+
)}
|
|
243
|
+
</Button>
|
|
217
244
|
</div>
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
</Button>
|
|
237
|
-
</div>
|
|
245
|
+
)}
|
|
246
|
+
</div>
|
|
247
|
+
|
|
248
|
+
{descriptionPreview && onDescriptionPreviewClick && (
|
|
249
|
+
<button
|
|
250
|
+
type="button"
|
|
251
|
+
data-testid="compact-task-description-preview"
|
|
252
|
+
aria-label={
|
|
253
|
+
descriptionPreviewLabel ??
|
|
254
|
+
t('ws-task-boards.dialog.open_fullscreen')
|
|
255
|
+
}
|
|
256
|
+
className="absolute top-full left-1/2 mt-2 w-full max-w-[30rem] -translate-x-1/2 rounded-lg border bg-background/95 px-4 py-3 text-left opacity-70 shadow-xl ring-1 ring-border/60 backdrop-blur transition hover:bg-muted/70 hover:opacity-100 focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
257
|
+
onClick={onDescriptionPreviewClick}
|
|
258
|
+
>
|
|
259
|
+
<span className="line-clamp-3 whitespace-pre-line text-muted-foreground text-sm leading-relaxed">
|
|
260
|
+
{descriptionPreview}
|
|
261
|
+
</span>
|
|
262
|
+
</button>
|
|
238
263
|
)}
|
|
239
264
|
</div>
|
|
240
265
|
);
|
package/src/components/ui/tu-do/shared/task-edit-dialog/components/task-description-editor.tsx
CHANGED
|
@@ -4,6 +4,7 @@ import type { QueryClient } from '@tanstack/react-query';
|
|
|
4
4
|
import type { Editor, JSONContent } from '@tiptap/react';
|
|
5
5
|
import { Loader2 } from '@tuturuuu/icons';
|
|
6
6
|
import type { TaskList } from '@tuturuuu/types/primitives/TaskList';
|
|
7
|
+
import { getBoardRealtimeChannelName } from '@tuturuuu/ui/hooks/useBoardRealtime.types';
|
|
7
8
|
import { toast } from '@tuturuuu/ui/sonner';
|
|
8
9
|
import { cn } from '@tuturuuu/utils/format';
|
|
9
10
|
import { useTranslations } from 'next-intl';
|
|
@@ -352,8 +353,9 @@ export function TaskDescriptionEditor({
|
|
|
352
353
|
|
|
353
354
|
{showCollaborationCursors && taskId && (
|
|
354
355
|
<CursorOverlayMultiWrapper
|
|
355
|
-
channelName={
|
|
356
|
+
channelName={getBoardRealtimeChannelName(boardId)}
|
|
356
357
|
containerRef={richTextEditorRef}
|
|
358
|
+
cursorScope={{ taskId, type: 'task-description' }}
|
|
357
359
|
/>
|
|
358
360
|
)}
|
|
359
361
|
|
|
@@ -373,8 +373,9 @@ function DescriptionDiff({
|
|
|
373
373
|
</>
|
|
374
374
|
);
|
|
375
375
|
|
|
376
|
-
//
|
|
377
|
-
|
|
376
|
+
// Show the full viewer whenever either side has content so users can inspect
|
|
377
|
+
// content-only, empty/content, and structural editor changes.
|
|
378
|
+
if (hasSnapshot || hasCurrent || hasTextChanges) {
|
|
378
379
|
return (
|
|
379
380
|
<div className="text-sm">
|
|
380
381
|
<div className="flex items-center gap-2">
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import '@testing-library/jest-dom/vitest';
|
|
2
|
+
|
|
3
|
+
import { fireEvent, render, screen } from '@testing-library/react';
|
|
4
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
5
|
+
import { SelectiveRevertPanel } from './selective-revert-panel';
|
|
6
|
+
|
|
7
|
+
vi.mock('./description-diff-viewer', () => ({
|
|
8
|
+
DescriptionDiffViewer: () => (
|
|
9
|
+
<button type="button">view-description-diff</button>
|
|
10
|
+
),
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
const t = (key: string, options?: { defaultValue?: string }) => {
|
|
14
|
+
const messages: Record<string, string> = {
|
|
15
|
+
changed: 'Changed',
|
|
16
|
+
'field.description': 'Description',
|
|
17
|
+
'field.name': 'Name',
|
|
18
|
+
'field.priority': 'Priority',
|
|
19
|
+
unchanged_fields: 'Unchanged fields',
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
return messages[key] ?? options?.defaultValue ?? key;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const snapshot = {
|
|
26
|
+
assignees: [],
|
|
27
|
+
completed: false,
|
|
28
|
+
description: {
|
|
29
|
+
content: [
|
|
30
|
+
{
|
|
31
|
+
content: [{ text: 'Previous description', type: 'text' }],
|
|
32
|
+
type: 'paragraph',
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
type: 'doc',
|
|
36
|
+
},
|
|
37
|
+
end_date: null,
|
|
38
|
+
estimation_points: null,
|
|
39
|
+
id: 'task-1',
|
|
40
|
+
labels: [],
|
|
41
|
+
list_id: 'list-1',
|
|
42
|
+
list_name: 'Review',
|
|
43
|
+
name: 'Previous task name',
|
|
44
|
+
priority: 'normal' as const,
|
|
45
|
+
projects: [],
|
|
46
|
+
start_date: null,
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const currentTask = {
|
|
50
|
+
...snapshot,
|
|
51
|
+
description: {
|
|
52
|
+
content: [
|
|
53
|
+
{
|
|
54
|
+
content: [{ text: 'Current description', type: 'text' }],
|
|
55
|
+
type: 'paragraph',
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
type: 'doc',
|
|
59
|
+
},
|
|
60
|
+
list_name: 'Review',
|
|
61
|
+
name: 'Current task name',
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
describe('SelectiveRevertPanel', () => {
|
|
65
|
+
it('renders changed fields first and keeps unchanged fields collapsed', () => {
|
|
66
|
+
render(
|
|
67
|
+
<SelectiveRevertPanel
|
|
68
|
+
currentTask={currentTask}
|
|
69
|
+
isReverting={false}
|
|
70
|
+
onRevert={vi.fn()}
|
|
71
|
+
snapshot={snapshot}
|
|
72
|
+
t={t}
|
|
73
|
+
/>
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
expect(screen.getByText('Core Fields')).toBeInTheDocument();
|
|
77
|
+
expect(screen.getByText('Name')).toBeInTheDocument();
|
|
78
|
+
expect(screen.getByText('Description')).toBeInTheDocument();
|
|
79
|
+
expect(screen.getByText('view-description-diff')).toBeInTheDocument();
|
|
80
|
+
|
|
81
|
+
const unchangedButton = screen.getByRole('button', {
|
|
82
|
+
name: /Unchanged fields/i,
|
|
83
|
+
});
|
|
84
|
+
expect(unchangedButton).toBeInTheDocument();
|
|
85
|
+
expect(screen.queryByText('Priority')).not.toBeInTheDocument();
|
|
86
|
+
|
|
87
|
+
fireEvent.click(unchangedButton);
|
|
88
|
+
|
|
89
|
+
expect(screen.getByText('Priority')).toBeInTheDocument();
|
|
90
|
+
});
|
|
91
|
+
});
|