@tuturuuu/ui 0.8.0 → 0.10.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 +69 -0
- package/biome.json +1 -1
- package/package.json +74 -71
- 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/custom/__tests__/settings-dialog-search.test.ts +78 -0
- package/src/components/ui/custom/__tests__/settings-dialog-shell-compile-graph.test.ts +76 -0
- package/src/components/ui/custom/__tests__/settings-dialog-shell.test.tsx +3 -0
- package/src/components/ui/custom/__tests__/workspace-select-helpers.test.ts +46 -1
- 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/nav-link.test.tsx +165 -0
- package/src/components/ui/custom/nav-link.tsx +69 -11
- package/src/components/ui/custom/navigation.tsx +1 -0
- package/src/components/ui/custom/settings/task-settings.tsx +104 -0
- package/src/components/ui/custom/settings-dialog-search-loader.d.ts +5 -0
- package/src/components/ui/custom/settings-dialog-search-loader.js +3 -0
- package/src/components/ui/custom/settings-dialog-search.ts +75 -0
- package/src/components/ui/custom/settings-dialog-shell.tsx +65 -28
- package/src/components/ui/custom/theme-toggle.tsx +1 -1
- package/src/components/ui/custom/workspace-select-helpers.ts +23 -0
- package/src/components/ui/custom/workspace-select.tsx +25 -19
- 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 +1 -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-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/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 +93 -154
- package/src/components/ui/storefront/checkout-overlay.tsx +4 -5
- package/src/components/ui/storefront/listing-card.tsx +1 -1
- package/src/components/ui/storefront/merch-sections.tsx +70 -0
- package/src/components/ui/storefront/product-detail.tsx +1 -1
- package/src/components/ui/storefront/storefront-surface.test.tsx +106 -11
- package/src/components/ui/storefront/storefront-surface.tsx +101 -166
- package/src/components/ui/storefront/types.ts +4 -0
- package/src/components/ui/storefront/utils.ts +6 -0
- package/src/components/ui/text-editor/__tests__/extensions.test.ts +123 -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/editor.tsx +69 -14
- package/src/components/ui/text-editor/extensions.ts +8 -2
- package/src/components/ui/text-editor/highlight-extension.ts +22 -0
- package/src/components/ui/text-editor/tool-bar.tsx +9 -16
- package/src/components/ui/toast.tsx +1 -1
- package/src/components/ui/tu-do/boards/__tests__/board-share-dialog.test.tsx +286 -0
- package/src/components/ui/tu-do/boards/__tests__/task-board-form.test.tsx +12 -0
- 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 +15 -226
- package/src/components/ui/tu-do/boards/board-share-settings-panel.tsx +351 -0
- package/src/components/ui/tu-do/boards/boardId/board-column.tsx +121 -39
- package/src/components/ui/tu-do/boards/boardId/enhanced-task-list.tsx +7 -0
- 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/bulk/bulk-operation-types.ts +3 -3
- 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/data/use-bulk-resources.ts +59 -5
- 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/drag-preview.tsx +20 -1
- package/src/components/ui/tu-do/boards/boardId/kanban/dnd/task-drag-cache.ts +38 -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.ts +81 -30
- 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 +642 -5
- package/src/components/ui/tu-do/boards/boardId/kanban/rendering/kanban-columns.tsx +224 -15
- package/src/components/ui/tu-do/boards/boardId/kanban/rendering/kanban-deadline-panels.tsx +535 -53
- package/src/components/ui/tu-do/boards/boardId/kanban/rendering/kanban-skeleton.tsx +101 -33
- package/src/components/ui/tu-do/boards/boardId/kanban.tsx +235 -113
- package/src/components/ui/tu-do/boards/boardId/task-board-server-page.test.tsx +50 -5
- package/src/components/ui/tu-do/boards/boardId/task-board-server-page.tsx +12 -2
- package/src/components/ui/tu-do/boards/boardId/task-card/measured-task-card.tsx +10 -1
- 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-open-options.test.ts +20 -0
- package/src/components/ui/tu-do/boards/boardId/task-card/task-card-open-options.ts +10 -0
- package/src/components/ui/tu-do/boards/boardId/task-card/task-card.tsx +271 -36
- 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 +22 -0
- package/src/components/ui/tu-do/boards/boardId/timeline/timeline-grid.tsx +9 -0
- package/src/components/ui/tu-do/boards/boardId/timeline/timeline-task-row.tsx +9 -0
- package/src/components/ui/tu-do/boards/boardId/timeline/timeline-toolbar.tsx +9 -0
- package/src/components/ui/tu-do/boards/boardId/timeline-board.tsx +35 -3
- package/src/components/ui/tu-do/boards/form.tsx +1 -1
- package/src/components/ui/tu-do/boards/share-section.tsx +100 -0
- 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/hooks/__tests__/useTaskLabelManagement.test.tsx +48 -0
- package/src/components/ui/tu-do/hooks/__tests__/useTaskProjectManagement.test.tsx +144 -0
- package/src/components/ui/tu-do/hooks/useTaskDialog.ts +7 -0
- package/src/components/ui/tu-do/hooks/useTaskLabelManagement.ts +115 -106
- package/src/components/ui/tu-do/hooks/useTaskProjectManagement.ts +115 -122
- 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/progress/task-progress-import-panel.tsx +60 -0
- package/src/components/ui/tu-do/progress/task-progress-leaderboards-panel.tsx +156 -0
- package/src/components/ui/tu-do/progress/task-progress-page.tsx +348 -0
- package/src/components/ui/tu-do/progress/task-progress-panels.tsx +301 -0
- package/src/components/ui/tu-do/providers/task-dialog-provider.tsx +26 -0
- package/src/components/ui/tu-do/shared/__tests__/assignee-select.test.tsx +81 -10
- package/src/components/ui/tu-do/shared/__tests__/board-client.test.tsx +141 -1
- package/src/components/ui/tu-do/shared/__tests__/board-header.test.tsx +377 -36
- package/src/components/ui/tu-do/shared/__tests__/board-switcher.test.tsx +374 -0
- package/src/components/ui/tu-do/shared/__tests__/board-views.test.tsx +419 -5
- package/src/components/ui/tu-do/shared/__tests__/task-board-loading-state.test.tsx +38 -0
- package/src/components/ui/tu-do/shared/__tests__/task-cache-patches.test.ts +147 -0
- package/src/components/ui/tu-do/shared/__tests__/task-legacy-route-recovery.test.tsx +16 -0
- package/src/components/ui/tu-do/shared/__tests__/use-progressive-board-loader.test.tsx +3 -0
- package/src/components/ui/tu-do/shared/assignee-select.tsx +77 -26
- package/src/components/ui/tu-do/shared/board-client.tsx +15 -10
- package/src/components/ui/tu-do/shared/board-config-storage.ts +7 -1
- package/src/components/ui/tu-do/shared/board-header.tsx +471 -975
- package/src/components/ui/tu-do/shared/board-layout-settings.tsx +165 -136
- package/src/components/ui/tu-do/shared/board-switcher.tsx +244 -220
- package/src/components/ui/tu-do/shared/board-user-presence-avatars.tsx +18 -12
- package/src/components/ui/tu-do/shared/board-views.tsx +577 -85
- package/src/components/ui/tu-do/shared/list-view.tsx +246 -2
- 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-cache-patches.ts +394 -0
- package/src/components/ui/tu-do/shared/task-dialog-manager.tsx +21 -1
- package/src/components/ui/tu-do/shared/task-edit-dialog/components/quick-settings-popover.tsx +5 -1
- package/src/components/ui/tu-do/shared/task-edit-dialog/components/task-dialog-header.tsx +25 -2
- package/src/components/ui/tu-do/shared/task-edit-dialog/components/task-list-selector.tsx +7 -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/hooks/use-task-data.ts +79 -10
- package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/use-task-mutations.ts +76 -77
- package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/use-task-relationships.test.tsx +63 -0
- package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/use-task-relationships.ts +78 -69
- package/src/components/ui/tu-do/shared/task-edit-dialog/personal-overrides-section.tsx +28 -8
- package/src/components/ui/tu-do/shared/task-edit-dialog/relationships/dependencies-section.tsx +14 -3
- package/src/components/ui/tu-do/shared/task-edit-dialog/relationships/parent-section.tsx +6 -1
- package/src/components/ui/tu-do/shared/task-edit-dialog/relationships/related-section.tsx +6 -1
- package/src/components/ui/tu-do/shared/task-edit-dialog/relationships/subtasks-section.tsx +6 -1
- package/src/components/ui/tu-do/shared/task-edit-dialog/relationships/types/task-relationships.types.ts +8 -0
- 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-dialog-actions.tsx +8 -1
- package/src/components/ui/tu-do/shared/task-edit-dialog/task-properties-section.test.tsx +150 -0
- package/src/components/ui/tu-do/shared/task-edit-dialog/task-properties-section.tsx +61 -35
- package/src/components/ui/tu-do/shared/task-edit-dialog/task-relationships-properties.tsx +44 -2
- 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 +11 -1
- package/src/components/ui/tu-do/shared/task-legacy-route-recovery.tsx +2 -9
- package/src/components/ui/tu-do/shared/task-row-actions-menu.tsx +11 -0
- package/src/components/ui/tu-do/shared/use-progressive-board-loader.ts +2 -0
- 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__/useBoardPresence.test.tsx +191 -0
- package/src/hooks/__tests__/useBoardRealtime.test.tsx +24 -144
- 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/useBoardPresence.ts +364 -0
- package/src/hooks/useBoardRealtimeEventHandler.ts +45 -90
- package/src/lib/workspace-actions.ts +2 -6
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { useQuery } from '@tanstack/react-query';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
listWorkspaceTaskBoardViewableMembers,
|
|
4
|
+
listWorkspaceTaskProjects,
|
|
5
|
+
} from '@tuturuuu/internal-api/tasks';
|
|
3
6
|
import { createClient } from '@tuturuuu/supabase/next/client';
|
|
4
7
|
import type { TaskList } from '@tuturuuu/types/primitives/TaskList';
|
|
5
8
|
import {
|
|
@@ -89,10 +92,19 @@ interface UseTaskDataProps {
|
|
|
89
92
|
isOpen: boolean;
|
|
90
93
|
propAvailableLists?: TaskList[];
|
|
91
94
|
taskSearchQuery?: string;
|
|
95
|
+
canUseBoardAssignees?: boolean;
|
|
96
|
+
assigneeMemberSource?: 'workspace' | 'board' | 'workspace-and-board';
|
|
92
97
|
/** Pre-loaded data for shared task context - bypasses internal fetches when provided */
|
|
93
98
|
sharedContext?: SharedTaskContext;
|
|
94
99
|
}
|
|
95
100
|
|
|
101
|
+
type TaskDialogWorkspaceMember = {
|
|
102
|
+
id: string;
|
|
103
|
+
user_id: string;
|
|
104
|
+
display_name: string;
|
|
105
|
+
avatar_url?: string | null;
|
|
106
|
+
};
|
|
107
|
+
|
|
96
108
|
// UUID validation regex
|
|
97
109
|
const UUID_REGEX =
|
|
98
110
|
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -107,6 +119,8 @@ export function useTaskData({
|
|
|
107
119
|
isOpen,
|
|
108
120
|
propAvailableLists,
|
|
109
121
|
taskSearchQuery = '',
|
|
122
|
+
canUseBoardAssignees,
|
|
123
|
+
assigneeMemberSource,
|
|
110
124
|
sharedContext,
|
|
111
125
|
}: UseTaskDataProps) {
|
|
112
126
|
// If sharedContext is provided, use pre-loaded data and skip fetches
|
|
@@ -174,17 +188,19 @@ export function useTaskData({
|
|
|
174
188
|
);
|
|
175
189
|
const workspaceLabels =
|
|
176
190
|
sharedContext?.workspaceLabels || fetchedWorkspaceLabels;
|
|
191
|
+
const effectiveAssigneeMemberSource = assigneeMemberSource ?? 'workspace';
|
|
192
|
+
const shouldLoadWorkspaceMembers =
|
|
193
|
+
canUseBoardAssignees !== false && effectiveAssigneeMemberSource !== 'board';
|
|
194
|
+
const shouldLoadBoardViewableMembers =
|
|
195
|
+
canUseBoardAssignees !== false &&
|
|
196
|
+
effectiveAssigneeMemberSource !== 'workspace' &&
|
|
197
|
+
!!boardId;
|
|
177
198
|
|
|
178
199
|
// Workspace members
|
|
179
200
|
const { data: fetchedWorkspaceMembers = [] } = useQuery<
|
|
180
|
-
|
|
181
|
-
id: string;
|
|
182
|
-
user_id: string;
|
|
183
|
-
display_name: string;
|
|
184
|
-
avatar_url?: string | null;
|
|
185
|
-
}>
|
|
201
|
+
TaskDialogWorkspaceMember[]
|
|
186
202
|
>({
|
|
187
|
-
queryKey: ['workspace-members', realWorkspaceId],
|
|
203
|
+
queryKey: ['workspace-members', realWorkspaceId, 'workspace'],
|
|
188
204
|
queryFn: async () => {
|
|
189
205
|
if (!realWorkspaceId || !isValidWsId) return [];
|
|
190
206
|
|
|
@@ -234,11 +250,64 @@ export function useTaskData({
|
|
|
234
250
|
(a.display_name || '').localeCompare(b.display_name || '')
|
|
235
251
|
);
|
|
236
252
|
},
|
|
237
|
-
enabled:
|
|
253
|
+
enabled:
|
|
254
|
+
!!realWorkspaceId &&
|
|
255
|
+
isOpen &&
|
|
256
|
+
isValidWsId &&
|
|
257
|
+
!hasSharedContext &&
|
|
258
|
+
shouldLoadWorkspaceMembers,
|
|
259
|
+
staleTime: 5 * 60 * 1000, // 5 minutes
|
|
260
|
+
});
|
|
261
|
+
const { data: fetchedBoardViewableMembers = [] } = useQuery<
|
|
262
|
+
TaskDialogWorkspaceMember[]
|
|
263
|
+
>({
|
|
264
|
+
queryKey: ['task-board-viewable-members', realWorkspaceId, boardId],
|
|
265
|
+
queryFn: async () => {
|
|
266
|
+
if (!realWorkspaceId || !isValidWsId || !boardId) return [];
|
|
267
|
+
|
|
268
|
+
const payload = await listWorkspaceTaskBoardViewableMembers(
|
|
269
|
+
realWorkspaceId,
|
|
270
|
+
boardId
|
|
271
|
+
);
|
|
272
|
+
const members = Array.isArray(payload?.members) ? payload.members : [];
|
|
273
|
+
|
|
274
|
+
return members
|
|
275
|
+
.map((member) => ({
|
|
276
|
+
id: member.user_id,
|
|
277
|
+
user_id: member.user_id,
|
|
278
|
+
display_name: member.display_name || member.email || member.user_id,
|
|
279
|
+
avatar_url: member.avatar_url,
|
|
280
|
+
}))
|
|
281
|
+
.sort((a, b) =>
|
|
282
|
+
(a.display_name || '').localeCompare(b.display_name || '')
|
|
283
|
+
);
|
|
284
|
+
},
|
|
285
|
+
enabled:
|
|
286
|
+
!!realWorkspaceId &&
|
|
287
|
+
isOpen &&
|
|
288
|
+
isValidWsId &&
|
|
289
|
+
!hasSharedContext &&
|
|
290
|
+
shouldLoadBoardViewableMembers,
|
|
238
291
|
staleTime: 5 * 60 * 1000, // 5 minutes
|
|
239
292
|
});
|
|
293
|
+
const mergedFetchedWorkspaceMembers = useMemo(() => {
|
|
294
|
+
const seen = new Set<string>();
|
|
295
|
+
const merged: TaskDialogWorkspaceMember[] = [];
|
|
296
|
+
|
|
297
|
+
for (const member of [
|
|
298
|
+
...fetchedWorkspaceMembers,
|
|
299
|
+
...fetchedBoardViewableMembers,
|
|
300
|
+
]) {
|
|
301
|
+
const memberId = member.user_id || member.id;
|
|
302
|
+
if (!memberId || seen.has(memberId)) continue;
|
|
303
|
+
seen.add(memberId);
|
|
304
|
+
merged.push(member);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return merged;
|
|
308
|
+
}, [fetchedBoardViewableMembers, fetchedWorkspaceMembers]);
|
|
240
309
|
const workspaceMembers =
|
|
241
|
-
sharedContext?.workspaceMembers ||
|
|
310
|
+
sharedContext?.workspaceMembers || mergedFetchedWorkspaceMembers;
|
|
242
311
|
|
|
243
312
|
// Task projects
|
|
244
313
|
const { data: fetchedTaskProjects = [] } = useQuery({
|
|
@@ -6,13 +6,17 @@ import {
|
|
|
6
6
|
import type { TaskPriority } from '@tuturuuu/types/primitives/Priority';
|
|
7
7
|
import type { CalendarHoursType } from '@tuturuuu/types/primitives/Task';
|
|
8
8
|
import { useToast } from '@tuturuuu/ui/hooks/use-toast';
|
|
9
|
-
import { invalidateTaskCaches } from '@tuturuuu/utils/task-helper';
|
|
10
9
|
import { useCallback, useState } from 'react';
|
|
11
10
|
import {
|
|
12
11
|
type BoardBroadcastFn,
|
|
13
12
|
getActiveBroadcast,
|
|
14
13
|
useBoardBroadcast,
|
|
15
14
|
} from '../../board-broadcast-context';
|
|
15
|
+
import {
|
|
16
|
+
patchTaskInVisibleCaches,
|
|
17
|
+
restoreVisibleTaskCaches,
|
|
18
|
+
snapshotVisibleTaskCaches,
|
|
19
|
+
} from '../../task-cache-patches';
|
|
16
20
|
import { updateWorkspaceTask } from './task-api';
|
|
17
21
|
|
|
18
22
|
export interface SchedulingSettings {
|
|
@@ -109,17 +113,17 @@ export function useTaskMutations({
|
|
|
109
113
|
return;
|
|
110
114
|
}
|
|
111
115
|
setEstimationSaving(true);
|
|
116
|
+
const cacheSnapshot = snapshotVisibleTaskCaches(queryClient, boardId, [
|
|
117
|
+
taskId,
|
|
118
|
+
]);
|
|
112
119
|
|
|
113
120
|
// Optimistic update - prevents flicker by updating cache immediately
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
);
|
|
121
|
-
}
|
|
122
|
-
);
|
|
121
|
+
patchTaskInVisibleCaches({
|
|
122
|
+
queryClient,
|
|
123
|
+
boardId,
|
|
124
|
+
taskId,
|
|
125
|
+
updater: (task) => ({ ...task, estimation_points: points }),
|
|
126
|
+
});
|
|
123
127
|
|
|
124
128
|
try {
|
|
125
129
|
const { task } = await updateWorkspaceTask(wsId, taskId, {
|
|
@@ -135,7 +139,7 @@ export function useTaskMutations({
|
|
|
135
139
|
} catch (e: any) {
|
|
136
140
|
console.error('Failed updating estimation', e);
|
|
137
141
|
// Revert optimistic update on error
|
|
138
|
-
|
|
142
|
+
restoreVisibleTaskCaches(queryClient, cacheSnapshot);
|
|
139
143
|
toast({
|
|
140
144
|
title: 'Failed to update estimation',
|
|
141
145
|
description: e.message || 'Please try again',
|
|
@@ -166,17 +170,17 @@ export function useTaskMutations({
|
|
|
166
170
|
if (isCreateMode || !taskId || taskId === 'new') {
|
|
167
171
|
return;
|
|
168
172
|
}
|
|
173
|
+
const cacheSnapshot = snapshotVisibleTaskCaches(queryClient, boardId, [
|
|
174
|
+
taskId,
|
|
175
|
+
]);
|
|
169
176
|
|
|
170
177
|
// Optimistic update - prevents flicker
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
);
|
|
178
|
-
}
|
|
179
|
-
);
|
|
178
|
+
patchTaskInVisibleCaches({
|
|
179
|
+
queryClient,
|
|
180
|
+
boardId,
|
|
181
|
+
taskId,
|
|
182
|
+
updater: (task) => ({ ...task, priority: newPriority }),
|
|
183
|
+
});
|
|
180
184
|
|
|
181
185
|
try {
|
|
182
186
|
const { task } = await updateWorkspaceTask(wsId, taskId, {
|
|
@@ -192,7 +196,7 @@ export function useTaskMutations({
|
|
|
192
196
|
} catch (e: any) {
|
|
193
197
|
console.error('Failed updating priority', e);
|
|
194
198
|
// Revert optimistic update on error
|
|
195
|
-
|
|
199
|
+
restoreVisibleTaskCaches(queryClient, cacheSnapshot);
|
|
196
200
|
toast({
|
|
197
201
|
title: 'Failed to update priority',
|
|
198
202
|
description: e.message || 'Please try again',
|
|
@@ -222,17 +226,17 @@ export function useTaskMutations({
|
|
|
222
226
|
}
|
|
223
227
|
|
|
224
228
|
const dateString = newDate ? newDate.toISOString() : null;
|
|
229
|
+
const cacheSnapshot = snapshotVisibleTaskCaches(queryClient, boardId, [
|
|
230
|
+
taskId,
|
|
231
|
+
]);
|
|
225
232
|
|
|
226
233
|
// Optimistic update - prevents flicker
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
);
|
|
234
|
-
}
|
|
235
|
-
);
|
|
234
|
+
patchTaskInVisibleCaches({
|
|
235
|
+
queryClient,
|
|
236
|
+
boardId,
|
|
237
|
+
taskId,
|
|
238
|
+
updater: (task) => ({ ...task, start_date: dateString ?? undefined }),
|
|
239
|
+
});
|
|
236
240
|
|
|
237
241
|
try {
|
|
238
242
|
const { task } = await updateWorkspaceTask(wsId, taskId, {
|
|
@@ -248,7 +252,7 @@ export function useTaskMutations({
|
|
|
248
252
|
} catch (e: any) {
|
|
249
253
|
console.error('Failed updating start date', e);
|
|
250
254
|
// Revert optimistic update on error
|
|
251
|
-
|
|
255
|
+
restoreVisibleTaskCaches(queryClient, cacheSnapshot);
|
|
252
256
|
toast({
|
|
253
257
|
title: 'Failed to update start date',
|
|
254
258
|
description: e.message || 'Please try again',
|
|
@@ -277,17 +281,17 @@ export function useTaskMutations({
|
|
|
277
281
|
}
|
|
278
282
|
|
|
279
283
|
const dateString = newDate ? newDate.toISOString() : null;
|
|
284
|
+
const cacheSnapshot = snapshotVisibleTaskCaches(queryClient, boardId, [
|
|
285
|
+
taskId,
|
|
286
|
+
]);
|
|
280
287
|
|
|
281
288
|
// Optimistic update - prevents flicker
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
);
|
|
289
|
-
}
|
|
290
|
-
);
|
|
289
|
+
patchTaskInVisibleCaches({
|
|
290
|
+
queryClient,
|
|
291
|
+
boardId,
|
|
292
|
+
taskId,
|
|
293
|
+
updater: (task) => ({ ...task, end_date: dateString }),
|
|
294
|
+
});
|
|
291
295
|
|
|
292
296
|
try {
|
|
293
297
|
const { task } = await updateWorkspaceTask(wsId, taskId, {
|
|
@@ -303,7 +307,7 @@ export function useTaskMutations({
|
|
|
303
307
|
} catch (e: any) {
|
|
304
308
|
console.error('Failed updating end date', e);
|
|
305
309
|
// Revert optimistic update on error
|
|
306
|
-
|
|
310
|
+
restoreVisibleTaskCaches(queryClient, cacheSnapshot);
|
|
307
311
|
toast({
|
|
308
312
|
title: 'Failed to update end date',
|
|
309
313
|
description: e.message || 'Please try again',
|
|
@@ -331,38 +335,33 @@ export function useTaskMutations({
|
|
|
331
335
|
if (isCreateMode || !taskId || taskId === 'new') {
|
|
332
336
|
return;
|
|
333
337
|
}
|
|
338
|
+
const cacheSnapshot = snapshotVisibleTaskCaches(queryClient, boardId, [
|
|
339
|
+
taskId,
|
|
340
|
+
]);
|
|
334
341
|
|
|
335
342
|
// Optimistic update - prevents flicker
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
);
|
|
343
|
-
}
|
|
344
|
-
);
|
|
343
|
+
patchTaskInVisibleCaches({
|
|
344
|
+
queryClient,
|
|
345
|
+
boardId,
|
|
346
|
+
taskId,
|
|
347
|
+
updater: (task) => ({ ...task, list_id: newListId }),
|
|
348
|
+
});
|
|
345
349
|
|
|
346
350
|
try {
|
|
347
351
|
const { task: updatedTask } = await updateWorkspaceTask(wsId, taskId, {
|
|
348
352
|
list_id: newListId,
|
|
349
353
|
});
|
|
350
354
|
// Update sender's own cache with DB-computed timestamps
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
}
|
|
362
|
-
: task
|
|
363
|
-
);
|
|
364
|
-
}
|
|
365
|
-
);
|
|
355
|
+
patchTaskInVisibleCaches({
|
|
356
|
+
queryClient,
|
|
357
|
+
boardId,
|
|
358
|
+
taskId,
|
|
359
|
+
updater: (task) => ({
|
|
360
|
+
...task,
|
|
361
|
+
completed_at: updatedTask.completed_at,
|
|
362
|
+
closed_at: updatedTask.closed_at,
|
|
363
|
+
}),
|
|
364
|
+
});
|
|
366
365
|
broadcast?.('task:upsert', {
|
|
367
366
|
task: {
|
|
368
367
|
id: taskId,
|
|
@@ -379,7 +378,7 @@ export function useTaskMutations({
|
|
|
379
378
|
} catch (e: any) {
|
|
380
379
|
console.error('Failed updating list', e);
|
|
381
380
|
// Revert optimistic update on error
|
|
382
|
-
|
|
381
|
+
restoreVisibleTaskCaches(queryClient, cacheSnapshot);
|
|
383
382
|
toast({
|
|
384
383
|
title: 'Failed to update list',
|
|
385
384
|
description: e.message || 'Please try again',
|
|
@@ -412,15 +411,15 @@ export function useTaskMutations({
|
|
|
412
411
|
|
|
413
412
|
// Optimistically update the cache instead of invalidating
|
|
414
413
|
// This prevents conflicts with realtime sync
|
|
415
|
-
queryClient
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
}
|
|
423
|
-
);
|
|
414
|
+
const cacheSnapshot = snapshotVisibleTaskCaches(queryClient, boardId, [
|
|
415
|
+
taskId,
|
|
416
|
+
]);
|
|
417
|
+
patchTaskInVisibleCaches({
|
|
418
|
+
queryClient,
|
|
419
|
+
boardId,
|
|
420
|
+
taskId,
|
|
421
|
+
updater: (task) => ({ ...task, name: trimmedName }),
|
|
422
|
+
});
|
|
424
423
|
|
|
425
424
|
try {
|
|
426
425
|
const { task } = await updateWorkspaceTask(wsId, taskId, {
|
|
@@ -432,8 +431,8 @@ export function useTaskMutations({
|
|
|
432
431
|
triggerRefresh();
|
|
433
432
|
} catch (e: any) {
|
|
434
433
|
console.error('Failed updating task name', e);
|
|
435
|
-
// Revert optimistic update
|
|
436
|
-
|
|
434
|
+
// Revert optimistic update without refetching visible board caches.
|
|
435
|
+
restoreVisibleTaskCaches(queryClient, cacheSnapshot);
|
|
437
436
|
toast({
|
|
438
437
|
title: 'Failed to update task name',
|
|
439
438
|
description: e.message || 'Please try again',
|
package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/use-task-relationships.test.tsx
CHANGED
|
@@ -146,4 +146,67 @@ describe('useTaskRelationships', () => {
|
|
|
146
146
|
])
|
|
147
147
|
).toEqual([newLabel, existingLabel]);
|
|
148
148
|
});
|
|
149
|
+
|
|
150
|
+
it('patches visible task caches when labels change without invalidating board task queries', async () => {
|
|
151
|
+
const cachedTask = {
|
|
152
|
+
id: 'task-1',
|
|
153
|
+
labels: [],
|
|
154
|
+
} as unknown as Task;
|
|
155
|
+
|
|
156
|
+
queryClient.setQueryData(['tasks', 'board-1'], [cachedTask]);
|
|
157
|
+
queryClient.setQueryData(['tasks-full', 'board-1', 'all'], [cachedTask]);
|
|
158
|
+
queryClient.setQueryData(['task', 'task-1'], cachedTask);
|
|
159
|
+
const invalidateSpy = vi.spyOn(queryClient, 'invalidateQueries');
|
|
160
|
+
|
|
161
|
+
const { result } = renderHook(
|
|
162
|
+
() =>
|
|
163
|
+
useTaskRelationships({
|
|
164
|
+
wsId: 'personal',
|
|
165
|
+
taskId: 'task-1',
|
|
166
|
+
isCreateMode: false,
|
|
167
|
+
boardId: 'board-1',
|
|
168
|
+
selectedLabels: [],
|
|
169
|
+
selectedAssignees: [],
|
|
170
|
+
selectedProjects: [],
|
|
171
|
+
newLabelName: '',
|
|
172
|
+
newLabelColor: '#14b8a6',
|
|
173
|
+
newProjectName: '',
|
|
174
|
+
setSelectedLabels: vi.fn(),
|
|
175
|
+
setSelectedAssignees: vi.fn(),
|
|
176
|
+
setSelectedProjects: vi.fn(),
|
|
177
|
+
setAvailableLabels: vi.fn(),
|
|
178
|
+
setNewLabelName: vi.fn(),
|
|
179
|
+
setNewLabelColor: vi.fn(),
|
|
180
|
+
setNewProjectName: vi.fn(),
|
|
181
|
+
setShowNewLabelDialog: vi.fn(),
|
|
182
|
+
setShowNewProjectDialog: vi.fn(),
|
|
183
|
+
onUpdate: vi.fn(),
|
|
184
|
+
}),
|
|
185
|
+
{ wrapper }
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
await act(async () => {
|
|
189
|
+
await result.current.toggleLabel(newLabel);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
expect(
|
|
193
|
+
queryClient.getQueryData<Task[]>(['tasks', 'board-1'])?.[0]?.labels
|
|
194
|
+
).toEqual([newLabel]);
|
|
195
|
+
expect(
|
|
196
|
+
queryClient.getQueryData<Task[]>(['tasks-full', 'board-1', 'all'])?.[0]
|
|
197
|
+
?.labels
|
|
198
|
+
).toEqual([newLabel]);
|
|
199
|
+
expect(queryClient.getQueryData<Task>(['task', 'task-1'])?.labels).toEqual([
|
|
200
|
+
newLabel,
|
|
201
|
+
]);
|
|
202
|
+
expect(invalidateSpy).not.toHaveBeenCalledWith({
|
|
203
|
+
queryKey: ['tasks', 'board-1'],
|
|
204
|
+
});
|
|
205
|
+
expect(invalidateSpy).not.toHaveBeenCalledWith({
|
|
206
|
+
queryKey: ['tasks-full', 'board-1'],
|
|
207
|
+
});
|
|
208
|
+
expect(mocks.broadcast).toHaveBeenCalledWith('task:relations-changed', {
|
|
209
|
+
taskId: 'task-1',
|
|
210
|
+
});
|
|
211
|
+
});
|
|
149
212
|
});
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { type QueryClient, useQueryClient } from '@tanstack/react-query';
|
|
2
|
-
import type { Task } from '@tuturuuu/types/primitives/Task';
|
|
3
2
|
import { toast } from '@tuturuuu/ui/sonner';
|
|
4
|
-
import { invalidateTaskCaches } from '@tuturuuu/utils/task-helper';
|
|
5
3
|
import {
|
|
6
4
|
type Dispatch,
|
|
7
5
|
type SetStateAction,
|
|
@@ -11,9 +9,11 @@ import {
|
|
|
11
9
|
import { getRandomNewLabelColor } from '../../../utils/taskConstants';
|
|
12
10
|
import {
|
|
13
11
|
type BoardBroadcastFn,
|
|
12
|
+
getActiveBoardRefresh,
|
|
14
13
|
getActiveBroadcast,
|
|
15
14
|
useBoardBroadcast,
|
|
16
15
|
} from '../../board-broadcast-context';
|
|
16
|
+
import { patchTaskInVisibleCaches } from '../../task-cache-patches';
|
|
17
17
|
import type {
|
|
18
18
|
WorkspaceTaskAssignee,
|
|
19
19
|
WorkspaceTaskLabel,
|
|
@@ -129,6 +129,32 @@ function upsertWorkspaceLabelCaches({
|
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
function normalizeTaskAssignees(assignees: WorkspaceTaskAssignee[]) {
|
|
133
|
+
return assignees
|
|
134
|
+
.map((assignee) => {
|
|
135
|
+
const id = assignee.user_id || assignee.id;
|
|
136
|
+
if (!id) return null;
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
id,
|
|
140
|
+
display_name: assignee.display_name ?? undefined,
|
|
141
|
+
email: assignee.email ?? undefined,
|
|
142
|
+
avatar_url: assignee.avatar_url ?? undefined,
|
|
143
|
+
};
|
|
144
|
+
})
|
|
145
|
+
.filter((assignee): assignee is NonNullable<typeof assignee> =>
|
|
146
|
+
Boolean(assignee)
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function normalizeTaskProjects(projects: WorkspaceTaskProject[]) {
|
|
151
|
+
return projects.map((project) => ({
|
|
152
|
+
id: project.id,
|
|
153
|
+
name: project.name,
|
|
154
|
+
status: project.status ?? 'unknown',
|
|
155
|
+
}));
|
|
156
|
+
}
|
|
157
|
+
|
|
132
158
|
export function useTaskRelationships({
|
|
133
159
|
wsId,
|
|
134
160
|
labelCacheWorkspaceId,
|
|
@@ -189,9 +215,18 @@ export function useTaskRelationships({
|
|
|
189
215
|
});
|
|
190
216
|
|
|
191
217
|
setSelectedLabels(nextSelectedLabels);
|
|
192
|
-
|
|
218
|
+
patchTaskInVisibleCaches({
|
|
219
|
+
queryClient,
|
|
220
|
+
boardId,
|
|
221
|
+
taskId,
|
|
222
|
+
updater: (task) => ({
|
|
223
|
+
...task,
|
|
224
|
+
labels: nextSelectedLabels,
|
|
225
|
+
}),
|
|
226
|
+
});
|
|
193
227
|
queryClient.invalidateQueries({ queryKey: ['task-history'] });
|
|
194
228
|
broadcast?.('task:relations-changed', { taskId });
|
|
229
|
+
getActiveBoardRefresh()?.({ invalidateTasks: false });
|
|
195
230
|
onUpdate();
|
|
196
231
|
} catch (error: unknown) {
|
|
197
232
|
toast.error('Label update failed', {
|
|
@@ -246,30 +281,18 @@ export function useTaskRelationships({
|
|
|
246
281
|
});
|
|
247
282
|
|
|
248
283
|
setSelectedAssignees(nextSelectedAssignees);
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
: [
|
|
259
|
-
...currentAssignees,
|
|
260
|
-
{
|
|
261
|
-
id: userId,
|
|
262
|
-
display_name: member.display_name,
|
|
263
|
-
email: member.email,
|
|
264
|
-
avatar_url: member.avatar_url,
|
|
265
|
-
},
|
|
266
|
-
];
|
|
267
|
-
return { ...task, assignees: newAssignees };
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
);
|
|
284
|
+
patchTaskInVisibleCaches({
|
|
285
|
+
queryClient,
|
|
286
|
+
boardId,
|
|
287
|
+
taskId,
|
|
288
|
+
updater: (task) => ({
|
|
289
|
+
...task,
|
|
290
|
+
assignees: normalizeTaskAssignees(nextSelectedAssignees),
|
|
291
|
+
}),
|
|
292
|
+
});
|
|
271
293
|
queryClient.invalidateQueries({ queryKey: ['task-history'] });
|
|
272
294
|
broadcast?.('task:relations-changed', { taskId });
|
|
295
|
+
getActiveBoardRefresh()?.({ invalidateTasks: false });
|
|
273
296
|
onUpdate();
|
|
274
297
|
} catch (error: unknown) {
|
|
275
298
|
toast.error('Assignee update failed', {
|
|
@@ -315,22 +338,18 @@ export function useTaskRelationships({
|
|
|
315
338
|
});
|
|
316
339
|
|
|
317
340
|
setSelectedProjects(nextSelectedProjects);
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
: [...currentProjects, project];
|
|
328
|
-
return { ...task, projects: newProjects };
|
|
329
|
-
});
|
|
330
|
-
}
|
|
331
|
-
);
|
|
341
|
+
patchTaskInVisibleCaches({
|
|
342
|
+
queryClient,
|
|
343
|
+
boardId,
|
|
344
|
+
taskId,
|
|
345
|
+
updater: (task) => ({
|
|
346
|
+
...task,
|
|
347
|
+
projects: normalizeTaskProjects(nextSelectedProjects),
|
|
348
|
+
}),
|
|
349
|
+
});
|
|
332
350
|
queryClient.invalidateQueries({ queryKey: ['task-history'] });
|
|
333
351
|
broadcast?.('task:relations-changed', { taskId });
|
|
352
|
+
getActiveBoardRefresh()?.({ invalidateTasks: false });
|
|
334
353
|
onUpdate();
|
|
335
354
|
} catch (error: unknown) {
|
|
336
355
|
toast.error('Project update failed', {
|
|
@@ -393,23 +412,17 @@ export function useTaskRelationships({
|
|
|
393
412
|
});
|
|
394
413
|
|
|
395
414
|
setSelectedLabels(nextSelectedLabels);
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
labels: [...currentLabels, newLabel].sort((a, b) =>
|
|
406
|
-
compareLabelsByName(a, b)
|
|
407
|
-
),
|
|
408
|
-
};
|
|
409
|
-
});
|
|
410
|
-
}
|
|
411
|
-
);
|
|
415
|
+
patchTaskInVisibleCaches({
|
|
416
|
+
queryClient,
|
|
417
|
+
boardId,
|
|
418
|
+
taskId,
|
|
419
|
+
updater: (task) => ({
|
|
420
|
+
...task,
|
|
421
|
+
labels: nextSelectedLabels,
|
|
422
|
+
}),
|
|
423
|
+
});
|
|
412
424
|
broadcast?.('task:relations-changed', { taskId });
|
|
425
|
+
getActiveBoardRefresh()?.({ invalidateTasks: false });
|
|
413
426
|
onUpdate();
|
|
414
427
|
toast.success('Label created & linked', {
|
|
415
428
|
description: 'New label added and attached to this task.',
|
|
@@ -485,21 +498,17 @@ export function useTaskRelationships({
|
|
|
485
498
|
});
|
|
486
499
|
|
|
487
500
|
setSelectedProjects(nextSelectedProjects);
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
projects: [...currentProjects, newProject],
|
|
498
|
-
};
|
|
499
|
-
});
|
|
500
|
-
}
|
|
501
|
-
);
|
|
501
|
+
patchTaskInVisibleCaches({
|
|
502
|
+
queryClient,
|
|
503
|
+
boardId,
|
|
504
|
+
taskId,
|
|
505
|
+
updater: (task) => ({
|
|
506
|
+
...task,
|
|
507
|
+
projects: normalizeTaskProjects(nextSelectedProjects),
|
|
508
|
+
}),
|
|
509
|
+
});
|
|
502
510
|
broadcast?.('task:relations-changed', { taskId });
|
|
511
|
+
getActiveBoardRefresh()?.({ invalidateTasks: false });
|
|
503
512
|
onUpdate();
|
|
504
513
|
toast.success('Project created & linked', {
|
|
505
514
|
description: 'New project added and attached to this task.',
|