@taskforcehq/taskforce 0.3.302 → 0.3.304
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/dist/Taskforce.module.css +113 -5
- package/dist/TaskforceCore.js +560 -208
- package/dist/TaskforceCore.test.js +1833 -91
- package/dist/annotatedAttachments/service.d.ts +1 -1
- package/dist/annotatedAttachments/types.d.ts +1 -1
- package/dist/components/features/AgentsModule.js +1 -1
- package/dist/components/features/AgentsModule.test.js +1 -1
- package/dist/components/features/TaskSettings.js +58 -38
- package/dist/components/features/TaskSettings.test.js +139 -40
- package/dist/components/task/TaskActionHeader.d.ts +2 -1
- package/dist/components/task/TaskActionHeader.js +3 -3
- package/dist/components/task/TaskActionHeader.test.js +8 -0
- package/dist/components/task/TaskCard.js +16 -1
- package/dist/components/task/TaskCard.test.js +31 -0
- package/dist/components/task/TaskForm.d.ts +2 -1
- package/dist/components/task/TaskForm.js +22 -4
- package/dist/components/task/TaskForm.test.js +46 -0
- package/dist/components/task/TaskKanban.d.ts +1 -1
- package/dist/components/task/TaskKanban.js +31 -160
- package/dist/components/task/TaskKanban.test.js +17 -0
- package/dist/components/task/TaskStatusActions.d.ts +6 -1
- package/dist/components/task/TaskStatusActions.js +8 -3
- package/dist/components/task/TaskStatusActions.test.js +9 -0
- package/dist/components/task/taskKanbanDropRules.d.ts +58 -0
- package/dist/components/task/taskKanbanDropRules.js +187 -0
- package/dist/components/task/taskKanbanDropRules.test.d.ts +1 -0
- package/dist/components/task/taskKanbanDropRules.test.js +114 -0
- package/dist/components/ui/Modal.d.ts +1 -1
- package/dist/components/ui/Modal.js +1 -0
- package/dist/components/views/AppShellHeader.js +5 -1
- package/dist/components/views/AppShellHeader.test.js +4 -0
- package/dist/components/views/PlanComparisonPage.d.ts +3 -2
- package/dist/components/views/PlanComparisonPage.js +4 -2
- package/dist/components/views/PlanComparisonPage.test.js +4 -0
- package/dist/components/views/PlansPage.d.ts +7 -1
- package/dist/components/views/PlansPage.js +139 -53
- package/dist/components/views/PlansPage.test.d.ts +1 -0
- package/dist/components/views/PlansPage.test.js +157 -0
- package/dist/components/views/StandaloneLayout.d.ts +1 -0
- package/dist/components/views/StandaloneLayout.js +216 -186
- package/dist/components/views/WidgetView.js +11 -2
- package/dist/components/views/standalone/modals/AccountHubModal.d.ts +8 -3
- package/dist/components/views/standalone/modals/AccountHubModal.js +16 -2
- package/dist/components/views/standalone/modals/AccountHubModal.test.d.ts +1 -0
- package/dist/components/views/standalone/modals/AccountHubModal.test.js +26 -0
- package/dist/components/views/standalone/modals/SyncStatusModal.js +1 -1
- package/dist/core/DeletedTaskLifecycleService.d.ts +2 -1
- package/dist/core/EntitlementsPolicy.test.js +2 -2
- package/dist/core/GlobalSettingsService.js +78 -18
- package/dist/core/PlanEntitlementService.d.ts +31 -5
- package/dist/core/PlanEntitlementService.js +350 -222
- package/dist/core/SignupMonetizationSettings.test.js +208 -49
- package/dist/core/SystemAdmin.test.js +186 -96
- package/dist/core/TaskActivityService.d.ts +4 -1
- package/dist/core/TaskActivityService.js +45 -0
- package/dist/core/TaskAuditTimeline.test.js +52 -1
- package/dist/core/Taskforce.d.ts +65 -20
- package/dist/core/Taskforce.js +261 -51
- package/dist/core/Taskforce.mcpAuth.test.js +0 -2
- package/dist/core/UserProfileAvatarDrafts.test.js +12 -3
- package/dist/core/WorkspacePlanMode.test.js +65 -0
- package/dist/core/types.d.ts +11 -12
- package/dist/documentReviews/service.d.ts +1 -1
- package/dist/documentReviews/types.d.ts +1 -1
- package/dist/hooks/auth/useTaskforceAuthBootstrap.d.ts +48 -0
- package/dist/hooks/auth/useTaskforceAuthBootstrap.js +219 -0
- package/dist/hooks/sync/auth.d.ts +37 -0
- package/dist/hooks/sync/auth.js +61 -0
- package/dist/hooks/sync/bootstrap.d.ts +34 -0
- package/dist/hooks/sync/bootstrap.js +52 -0
- package/dist/hooks/sync/orchestratorShared.d.ts +36 -0
- package/dist/hooks/sync/orchestratorShared.js +209 -0
- package/dist/hooks/sync/orchestratorShared.test.d.ts +1 -0
- package/dist/hooks/sync/orchestratorShared.test.js +49 -0
- package/dist/hooks/sync/realtime.d.ts +25 -0
- package/dist/hooks/sync/realtime.js +60 -0
- package/dist/hooks/sync/recovery.d.ts +69 -0
- package/dist/hooks/sync/recovery.js +118 -0
- package/dist/hooks/sync/transfers.d.ts +122 -0
- package/dist/hooks/sync/transfers.js +431 -0
- package/dist/hooks/sync/useDataVersionRefresh.d.ts +16 -0
- package/dist/hooks/sync/useDataVersionRefresh.js +73 -0
- package/dist/hooks/ui/useResourceExport.d.ts +3 -1
- package/dist/hooks/ui/useResourceExport.js +5 -2
- package/dist/hooks/ui/useWorkflowTemplates.js +11 -6
- package/dist/hooks/useRealtimeSync.js +2 -1
- package/dist/hooks/useSyncOrchestrator.aiProfiles.test.js +8 -0
- package/dist/hooks/useSyncOrchestrator.context-assets.test.d.ts +1 -0
- package/dist/hooks/useSyncOrchestrator.context-assets.test.js +228 -0
- package/dist/hooks/useSyncOrchestrator.d.ts +5 -4
- package/dist/hooks/useSyncOrchestrator.js +315 -860
- package/dist/hooks/useSyncOrchestrator.retry-closure.test.js +665 -8
- package/dist/hooks/useTaskMutations.js +45 -6
- package/dist/hooks/useTaskMutations.test.js +147 -0
- package/dist/hooks/useTaskforce.d.ts +11 -2
- package/dist/hooks/useTaskforce.js +290 -812
- package/dist/hooks/useWorkspaceSyncController.d.ts +1 -0
- package/dist/hooks/useWorkspaceSyncController.js +22 -10
- package/dist/hooks/workspace/useTaskforceApiRouting.test.js +17 -0
- package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.d.ts +166 -0
- package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +434 -0
- package/dist/hooks/workspace/workspaceLocalState.d.ts +19 -0
- package/dist/hooks/workspace/workspaceLocalState.js +100 -0
- package/dist/hooks/workspace/workspaceLocalState.test.d.ts +1 -0
- package/dist/hooks/workspace/workspaceLocalState.test.js +59 -0
- package/dist/localization/locales/en-US.js +2 -2
- package/dist/mcp/canonicalAssetHelpers.d.ts +70 -0
- package/dist/mcp/canonicalAssetHelpers.js +259 -0
- package/dist/mcp/clientIntegrations.d.ts +12 -1
- package/dist/mcp/clientIntegrations.js +161 -6
- package/dist/mcp/clientIntegrations.test.js +76 -4
- package/dist/mcp/documentHelpers.d.ts +100 -0
- package/dist/mcp/documentHelpers.js +161 -0
- package/dist/mcp/runtime.js +264 -505
- package/dist/mcp/runtime.test.js +353 -89
- package/dist/mcp/taskAttachmentHelpers.d.ts +41 -0
- package/dist/mcp/taskAttachmentHelpers.js +60 -0
- package/dist/mcp/taskAttachmentTypes.d.ts +37 -0
- package/dist/mcp/taskAttachmentTypes.js +1 -0
- package/dist/migrations/billingSchemaParity.test.js +3 -0
- package/dist/migrations/taskSchemaMigrations.js +15 -0
- package/dist/plugins/vite.js +1 -1
- package/dist/runtime/appGateDefinitions.d.ts +1 -1
- package/dist/runtime/appGateDefinitions.js +1 -1
- package/dist/server/index.cookieProxy.test.js +1 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +48 -3
- package/dist/server/index.test.js +14 -2
- package/dist/server/mockStripe.d.ts +1 -0
- package/dist/server/mockStripe.js +2 -0
- package/dist/server/routes/admin.js +91 -40
- package/dist/server/routes/auth.d.ts +1 -0
- package/dist/server/routes/auth.js +231 -55
- package/dist/server/routes/billing.js +473 -39
- package/dist/server/routes/billing.test.js +972 -37
- package/dist/server/routes/shared.d.ts +30 -0
- package/dist/server/routes/shared.js +31 -3
- package/dist/server/routes/sync.integration.test.js +180 -0
- package/dist/server/routes/sync.js +125 -242
- package/dist/server/routes/tasks.js +49 -7
- package/dist/server/routes.js +11 -22
- package/dist/server/routes.test.js +530 -81
- package/dist/shared/taskActor.d.ts +10 -0
- package/dist/shared/taskActor.js +1 -0
- package/dist/sync/cloudSyncApi.d.ts +1 -0
- package/dist/sync/collaborationSyncPayload.js +4 -0
- package/dist/sync/collaborationSyncPayload.test.js +8 -0
- package/dist/sync/collaborationSyncState.d.ts +3 -1
- package/dist/sync/collaborationSyncState.js +19 -0
- package/dist/sync/contentSyncState.d.ts +10 -0
- package/dist/sync/contentSyncState.js +277 -14
- package/dist/sync/syncApplyHandlers.d.ts +87 -1
- package/dist/sync/syncApplyHandlers.js +370 -8
- package/dist/sync/syncApplyHandlers.test.d.ts +1 -0
- package/dist/sync/syncApplyHandlers.test.js +377 -0
- package/dist/sync/syncService.d.ts +9 -1
- package/dist/sync/syncService.js +57 -10
- package/dist/sync/syncService.test.js +48 -0
- package/dist/sync/workspacePullFeed.d.ts +11 -0
- package/dist/sync/workspacePullFeed.js +123 -68
- package/dist/sync/workspacePullFeed.test.js +180 -0
- package/dist/sync/workspaceSyncModel.d.ts +22 -1
- package/dist/sync/workspaceSyncModel.js +65 -0
- package/dist/sync/workspaceSyncModel.test.js +119 -0
- package/dist/types.d.ts +2 -10
- package/dist/ui/assets/AgentsModule-BLWVbuKP.js +1 -0
- package/dist/ui/assets/{AnnotatedAttachmentWorkspace-Dvi02Y7q.js → AnnotatedAttachmentWorkspace-BlS-cqnl.js} +1 -1
- package/dist/ui/assets/{DocumentWorkspace-iys3zfca.js → DocumentWorkspace-BH_6DF6x.js} +1 -1
- package/dist/ui/assets/{InitiativesModule-DJvLJI3A.js → InitiativesModule-BjR6iBf9.js} +1 -1
- package/dist/ui/assets/{PlansPage-BlVC_lRq.css → PlansPage-C2dd2n1X.css} +1 -1
- package/dist/ui/assets/PlansPage-CSDQ4sLa.js +1 -0
- package/dist/ui/assets/TaskSettings-CEDy34Jo.js +9 -0
- package/dist/ui/assets/{WorkflowsModule-BguHeQaV.js → WorkflowsModule-DnFqdUME.js} +1 -1
- package/dist/ui/assets/index-DXUdtH1B.js +6 -0
- package/dist/ui/assets/index-Ii0B0rTO.css +1 -0
- package/dist/ui/assets/{vendor-icons-C8EED3Oh.js → vendor-icons-I7ZwG1z_.js} +1 -1
- package/dist/ui/index.html +4 -4
- package/dist/utils/accountProfileSummaryCache.d.ts +31 -0
- package/dist/utils/accountProfileSummaryCache.js +97 -0
- package/dist/utils/accountProfileSummaryCache.test.d.ts +1 -0
- package/dist/utils/accountProfileSummaryCache.test.js +63 -0
- package/dist/utils/taskActivity.js +4 -0
- package/dist/utils/taskActivity.test.js +25 -1
- package/package.json +5 -3
- package/scripts/playwright-auth.sh +4 -0
- package/dist/ui/assets/AgentsModule-JG5jc3he.js +0 -1
- package/dist/ui/assets/PlansPage-BMPlpFpw.js +0 -1
- package/dist/ui/assets/TaskSettings-Bqd4cCzW.js +0 -8
- package/dist/ui/assets/index-MXeWoebC.css +0 -1
- package/dist/ui/assets/index-YJ4k5QNa.js +0 -6
- package/dist/utils/billingStatusCache.d.ts +0 -21
- package/dist/utils/billingStatusCache.js +0 -70
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
2
2
|
import React, { useMemo, useCallback, useState, useEffect, useRef, useLayoutEffect, Suspense } from 'react';
|
|
3
3
|
import { createPortal } from 'react-dom';
|
|
4
4
|
import { useLocation, useNavigate } from 'react-router-dom';
|
|
5
|
-
import { Settings, Plus, Filter, Layers, User, Maximize2, Minimize2, Check, ChevronLeft, ArrowUp, ArrowDown, ArrowUpDown, AlertTriangle, Save, Loader2, Folder, FileText, LogOut, NotebookTabs, ClipboardCheck, Cloud, CloudOff, Users, ChevronsUp, ChevronsDown, EyeOff, Zap, HelpCircle, Bot, Image, Workflow } from 'lucide-react';
|
|
5
|
+
import { Settings, Plus, Filter, Layers, User, Maximize2, Minimize2, Check, ChevronLeft, ArrowUp, ArrowDown, ArrowUpDown, AlertTriangle, Save, Loader2, Folder, FileText, LogOut, NotebookTabs, ClipboardCheck, Cloud, CloudOff, Users, ClockAlert, ChevronsUp, ChevronsDown, EyeOff, Zap, HelpCircle, Bot, Image, Workflow } from 'lucide-react';
|
|
6
6
|
import { STATUS_OPTIONS, getStatusDefinition } from '../../utils/constants';
|
|
7
7
|
import styles from '../../Taskforce.module.css';
|
|
8
8
|
import shellStyles from './WorkspaceShell.module.css';
|
|
@@ -33,11 +33,11 @@ import { getImageReferenceLabel } from '../../utils/imageReferences';
|
|
|
33
33
|
import { buildCustomTaxonomySortOptions } from '../../utils/taxonomySorting.js';
|
|
34
34
|
import { getLocale, t } from '../../localization';
|
|
35
35
|
import { resolveAnnotatedAttachmentDetail } from '../../utils/annotatedAttachments';
|
|
36
|
-
import {
|
|
36
|
+
import { ACCOUNT_PROFILE_SUMMARY_PATH, invalidateAccountProfileSummaryCache, loadAccountProfileSummaryCached } from '../../utils/accountProfileSummaryCache';
|
|
37
37
|
import { fetchTaskforceApi } from '../../utils/taskforceApiClient';
|
|
38
38
|
import { AppShellHeader } from './AppShellHeader';
|
|
39
39
|
import { getTaskforceCloudEnvironmentConfig, parseTaskforceCloudEnvironment, resolveTaskforceCloudEnvironmentFromBaseUrl } from '../../config/cloudEnvironment';
|
|
40
|
-
import { logBootstrapDebug } from '../../hooks/workspace/workspaceLocalState';
|
|
40
|
+
import { logBootstrapDebug, persistRemoteUiState } from '../../hooks/workspace/workspaceLocalState';
|
|
41
41
|
import { FilterToolbar } from './panels/FilterToolbar';
|
|
42
42
|
import { DocumentFilterToolbar } from './panels/DocumentFilterToolbar';
|
|
43
43
|
import { PlanningDrawer, getPlanningDrawerWidthPx, } from './panels/PlanningDrawer';
|
|
@@ -56,8 +56,10 @@ const WorkflowsModule = React.lazy(() => import('../features/WorkflowsModule').t
|
|
|
56
56
|
const AgentsModule = React.lazy(() => import('../features/AgentsModule').then(m => ({ default: m.AgentsModule })));
|
|
57
57
|
const InitiativesModule = React.lazy(() => import('../features/InitiativesModule').then(m => ({ default: m.InitiativesModule })));
|
|
58
58
|
const PlansPage = React.lazy(() => import('./PlansPage').then(m => ({ default: m.PlansPage })));
|
|
59
|
+
const ACTIVE_COMMERCIAL_STATES = new Set(['active', 'trialing', 'grace']);
|
|
59
60
|
const PROFILE_AVATAR_ACCEPT = 'image/png,image/jpeg,image/webp,image/gif';
|
|
60
61
|
const PROFILE_AVATAR_MAX_BYTES = 5 * 1024 * 1024;
|
|
62
|
+
const resolveSameOriginTaskforcePath = (path) => path;
|
|
61
63
|
function getSyncEventStableKey(event, index = 0) {
|
|
62
64
|
const explicitId = String(event.id ?? '').trim();
|
|
63
65
|
if (explicitId)
|
|
@@ -191,9 +193,6 @@ export function StandaloneLayout(props) {
|
|
|
191
193
|
const nextQuery = params.toString();
|
|
192
194
|
navigate(`${location.pathname === '/' ? '/' : location.pathname}${nextQuery ? `?${nextQuery}` : ''}${location.hash || ''}`);
|
|
193
195
|
}, [location.hash, location.pathname, location.search, navigate]);
|
|
194
|
-
const handlePlansBack = useCallback(() => {
|
|
195
|
-
closePlansScreen();
|
|
196
|
-
}, [closePlansScreen]);
|
|
197
196
|
const {
|
|
198
197
|
// State
|
|
199
198
|
activeTab, setActiveTab, activeCategories, groupBy, setGroupBy, activeWorkspaceModule, setActiveWorkspaceModule, emptyColumnMode, setEmptyColumnMode, zenMode, setZenMode, filterStatus, setFilterStatus,
|
|
@@ -215,7 +214,7 @@ export function StandaloneLayout(props) {
|
|
|
215
214
|
// clearFilters, // This was duplicated, removed one instance
|
|
216
215
|
// activeTypes, // This was duplicated, removed one instance
|
|
217
216
|
// Settings State & Props
|
|
218
|
-
settingsModel, configLoaded, currentTheme, setCurrentTheme, pathSaved, saveSettings, keyShortcut, setKeyShortcut, globalWeekStartsOn, locale, jsonBackupEnabled, setJsonBackupEnabled, mcpHostRoot, setMcpHostRoot, settingsSection, setSettingsSection, runtimeMode, workspaceSwitchingEnabled, cloudAuthConfigured, authRequiredForApi, authBlocked, isAuthenticated, authUserId, authWorkspaceId, authUserEmail, authUserDisplayName, authUserAvatarUrl, authSessionResolved, realtimeSyncEnabled, realtimeSyncFlagSource, workspaceCloudSyncEnabled, workspaceSyncPhase, workspaceSyncStatus, workspaceSyncSummary, workspaceSyncRecommendedAction, workspaceSyncBusy, workspaceSyncPendingChanges, saveWorkspaceCloudSyncSettings, pushNotice, userGlobalSyncStatus, workspaceLastSuccessfulSyncAt, workspaceLastPullAt, workspaceLastPushAt, workspaceLastErrorAt, userGlobalSyncError, workspaceLastErrorMessage, retryWorkspaceCloudSync, resetWorkspaceSyncCursorAndPull, getWorkspaceSyncDiagnostics, currentWorkspaceId, currentWorkspaceRole, availableWorkspaces, switchWorkspace, updateCurrentUserProfile, logout, projectRoot, projectName, mcpScriptPath, serverHostRoot,
|
|
217
|
+
settingsModel, configLoaded, currentTheme, setCurrentTheme, pathSaved, saveSettings, keyShortcut, setKeyShortcut, globalWeekStartsOn, locale, jsonBackupEnabled, setJsonBackupEnabled, mcpHostRoot, setMcpHostRoot, settingsSection, setSettingsSection, runtimeMode, workspaceSwitchingEnabled, cloudAuthConfigured, authRequiredForApi, authBlocked, isAuthenticated, authUserId, authWorkspaceId, authUserEmail, authUserDisplayName, authUserAvatarUrl, authSessionResolved, realtimeSyncEnabled, realtimeSyncFlagSource, workspaceCloudSyncEnabled, workspaceSyncPhase, workspaceSyncStatus, workspaceSyncSummary, workspaceSyncRecommendedAction, workspaceSyncBusy, workspaceSyncPendingChanges, saveWorkspaceCloudSyncSettings, pushNotice, userGlobalSyncStatus, workspaceLastSuccessfulSyncAt, workspaceLastPullAt, workspaceLastPushAt, workspaceLastErrorAt, userGlobalSyncError, workspaceLastErrorMessage, retryWorkspaceCloudSync, resetWorkspaceSyncCursorAndPull, getWorkspaceSyncDiagnostics, currentWorkspaceId, currentWorkspaceRole, availableWorkspaces, switchWorkspace, updateCurrentUserProfile, resolveCloudAuthUrl = resolveSameOriginTaskforcePath, logout, projectRoot, projectName, mcpScriptPath, serverHostRoot,
|
|
219
218
|
// Browser Props
|
|
220
219
|
showFolderBrowser, setShowFolderBrowser, folders, files, currentBrowsePath, fetchFolders, browserTarget, setBrowserTarget, handleSelectPath, handleAddPath, handleRemovePath,
|
|
221
220
|
// Settings Managers
|
|
@@ -503,34 +502,31 @@ export function StandaloneLayout(props) {
|
|
|
503
502
|
return;
|
|
504
503
|
const timeoutId = window.setTimeout(async () => {
|
|
505
504
|
try {
|
|
506
|
-
await
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
annotatedSessionId: requestedAnnotatedSessionId
|
|
532
|
-
}
|
|
533
|
-
})
|
|
505
|
+
await persistRemoteUiState({
|
|
506
|
+
stateKey: 'layout',
|
|
507
|
+
workspaceId: currentWorkspaceId,
|
|
508
|
+
headers: workspaceUiStateHeaders,
|
|
509
|
+
patch: {
|
|
510
|
+
scheduleShowWeekends,
|
|
511
|
+
scheduleShowBacklog,
|
|
512
|
+
scheduleOnlyExpired,
|
|
513
|
+
scheduleSidebarOpen,
|
|
514
|
+
scheduleSelectedDate,
|
|
515
|
+
scheduleCalendarMonth,
|
|
516
|
+
scheduleScrollLeft,
|
|
517
|
+
showFilters,
|
|
518
|
+
documentTypeFilters,
|
|
519
|
+
documentAttachmentFilters,
|
|
520
|
+
planningDrawerOpen,
|
|
521
|
+
planningTreeCollapsed,
|
|
522
|
+
planningPrimaryCollapsed,
|
|
523
|
+
planningSecondaryCollapsed,
|
|
524
|
+
planningExpandedInitiativeIds: Array.from(expandedPlanningInitiativeIds),
|
|
525
|
+
planningDrawerDetail,
|
|
526
|
+
planningNestedWorkstreamDetailId,
|
|
527
|
+
annotatedTarget: requestedAnnotatedTarget,
|
|
528
|
+
annotatedSessionId: requestedAnnotatedSessionId
|
|
529
|
+
}
|
|
534
530
|
});
|
|
535
531
|
}
|
|
536
532
|
catch {
|
|
@@ -804,9 +800,9 @@ export function StandaloneLayout(props) {
|
|
|
804
800
|
if (taskScope === 'deleted')
|
|
805
801
|
return deletedScopeAllTasks;
|
|
806
802
|
if (!showArchive)
|
|
807
|
-
return props.
|
|
808
|
-
return [...props.
|
|
809
|
-
}, [archivedScopeAllTasks, deletedScopeAllTasks, props.
|
|
803
|
+
return props.tasks;
|
|
804
|
+
return [...props.tasks, ...archivedScopeAllTasks];
|
|
805
|
+
}, [archivedScopeAllTasks, deletedScopeAllTasks, props.tasks, showArchive, taskScope]);
|
|
810
806
|
const hierarchyTasks = useMemo(() => {
|
|
811
807
|
const byId = new Map();
|
|
812
808
|
for (const task of archivedScopeAllTasks)
|
|
@@ -827,8 +823,13 @@ export function StandaloneLayout(props) {
|
|
|
827
823
|
assigneeOptions.forEach((option) => {
|
|
828
824
|
map.set(String(option.value), option.label);
|
|
829
825
|
});
|
|
826
|
+
const normalizedAuthUserId = String(authUserId || '').trim();
|
|
827
|
+
const normalizedAuthIdentityLabel = String(authUserDisplayName || authUserEmail || '').trim();
|
|
828
|
+
if (normalizedAuthUserId && normalizedAuthIdentityLabel) {
|
|
829
|
+
map.set(normalizedAuthUserId, normalizedAuthIdentityLabel);
|
|
830
|
+
}
|
|
830
831
|
return map;
|
|
831
|
-
}, [assigneeOptions]);
|
|
832
|
+
}, [assigneeOptions, authUserDisplayName, authUserEmail, authUserId]);
|
|
832
833
|
const planningStructure = useMemo(() => {
|
|
833
834
|
const planningScopedTasks = taskScope === 'archived'
|
|
834
835
|
? archivedScopeAllTasks
|
|
@@ -1036,6 +1037,11 @@ export function StandaloneLayout(props) {
|
|
|
1036
1037
|
return boardVisibleTasks;
|
|
1037
1038
|
return boardVisibleTasks.filter((task) => selectedPlanningTaskIds.has(task.id));
|
|
1038
1039
|
}, [boardVisibleTasks, selectedPlanningTaskIds]);
|
|
1040
|
+
const scopedKanbanAllTasks = useMemo(() => {
|
|
1041
|
+
if (!selectedPlanningTaskIds || selectedPlanningTaskIds.size === 0)
|
|
1042
|
+
return kanbanAllTasks;
|
|
1043
|
+
return kanbanAllTasks.filter((task) => selectedPlanningTaskIds.has(task.id));
|
|
1044
|
+
}, [kanbanAllTasks, selectedPlanningTaskIds]);
|
|
1039
1045
|
const expiredRecoveryCandidates = useMemo(() => {
|
|
1040
1046
|
if (groupBy !== 'schedule')
|
|
1041
1047
|
return [];
|
|
@@ -1218,11 +1224,12 @@ export function StandaloneLayout(props) {
|
|
|
1218
1224
|
const [teamAuditEvents, setTeamAuditEvents] = useState([]);
|
|
1219
1225
|
const [teamAuditHasMore, setTeamAuditHasMore] = useState(false);
|
|
1220
1226
|
const [teamAuditPages, setTeamAuditPages] = useState(1);
|
|
1221
|
-
const [
|
|
1227
|
+
const [accountProfileSummary, setAccountProfileSummary] = useState(null);
|
|
1222
1228
|
const [billingLoading, setBillingLoading] = useState(false);
|
|
1223
1229
|
const [billingError, setBillingError] = useState(null);
|
|
1224
1230
|
const [billingActionBusy, setBillingActionBusy] = useState(false);
|
|
1225
1231
|
const [billingActionError, setBillingActionError] = useState(null);
|
|
1232
|
+
const [plansNavigationBusy, setPlansNavigationBusy] = useState(false);
|
|
1226
1233
|
const [billingNotice, setBillingNotice] = useState(null);
|
|
1227
1234
|
const [billingIntervalChoice, setBillingIntervalChoice] = useState('month');
|
|
1228
1235
|
const [profileDisplayNameDraft, setProfileDisplayNameDraft] = useState('');
|
|
@@ -1240,7 +1247,11 @@ export function StandaloneLayout(props) {
|
|
|
1240
1247
|
billing: false,
|
|
1241
1248
|
teamManagement: false
|
|
1242
1249
|
});
|
|
1250
|
+
const accountProfileSummaryRef = useRef(null);
|
|
1243
1251
|
// showSearch state removed - search always visible in actions area
|
|
1252
|
+
useEffect(() => {
|
|
1253
|
+
accountProfileSummaryRef.current = accountProfileSummary;
|
|
1254
|
+
}, [accountProfileSummary]);
|
|
1244
1255
|
useEffect(() => {
|
|
1245
1256
|
if (!showAccountMenu)
|
|
1246
1257
|
return;
|
|
@@ -1291,33 +1302,17 @@ export function StandaloneLayout(props) {
|
|
|
1291
1302
|
const authIdentityLabel = authDisplayName || authEmailLabel;
|
|
1292
1303
|
const hasAuthIdentity = authIdentityLabel.length > 0;
|
|
1293
1304
|
const hasAuthEmail = authEmailLabel.length > 0;
|
|
1294
|
-
const accountBadgeLabel = (authIdentityLabel || authEmailLabel || '
|
|
1295
|
-
const
|
|
1305
|
+
const accountBadgeLabel = (authIdentityLabel || authEmailLabel || '').trim();
|
|
1306
|
+
const shouldShowResolvedAccountInitial = isAuthenticated && authSessionResolved && accountBadgeLabel.length > 0;
|
|
1307
|
+
const accountBadgeInitial = shouldShowResolvedAccountInitial ? accountBadgeLabel.charAt(0).toUpperCase() : '';
|
|
1296
1308
|
const accountAvatarUrl = authAvatarUrl;
|
|
1309
|
+
const shouldShowResolvedAccountAvatar = isAuthenticated && authSessionResolved && accountAvatarUrl.length > 0;
|
|
1297
1310
|
const profileAvatarDisplayUrl = String(profileAvatarPreviewUrl || authAvatarUrl).trim();
|
|
1298
|
-
const subscriptionLabel = String(
|
|
1311
|
+
const subscriptionLabel = String(accountProfileSummary?.planName || accountProfileSummary?.planId || '').trim();
|
|
1299
1312
|
const hasSubscription = subscriptionLabel.length > 0;
|
|
1300
|
-
const teamManagementWorkspaceId = String(authWorkspaceId || currentWorkspaceId || '').trim();
|
|
1313
|
+
const teamManagementWorkspaceId = String(accountProfileSummary?.workspaceId || authWorkspaceId || currentWorkspaceId || '').trim();
|
|
1301
1314
|
const runtimeLabel = runtimeMode === 'cloud' ? 'CLOUD' : 'LOCAL';
|
|
1302
1315
|
const apiBaseUrl = props.config?.apiBaseUrl || '';
|
|
1303
|
-
const accountCapabilityApiBaseUrl = useMemo(() => {
|
|
1304
|
-
const preferredBase = runtimeMode === 'local'
|
|
1305
|
-
? (props.config?.cloudAuthBaseUrl || props.config?.apiBaseUrl || '')
|
|
1306
|
-
: (props.config?.apiBaseUrl || props.config?.cloudAuthBaseUrl || '');
|
|
1307
|
-
return String(preferredBase || '').trim().replace(/\/+$/, '');
|
|
1308
|
-
}, [props.config?.apiBaseUrl, props.config?.cloudAuthBaseUrl, runtimeMode]);
|
|
1309
|
-
const billingApiBaseUrl = useMemo(() => {
|
|
1310
|
-
const preferredBase = runtimeMode === 'local'
|
|
1311
|
-
? (props.config?.cloudAuthBaseUrl || props.config?.apiBaseUrl || '')
|
|
1312
|
-
: (props.config?.apiBaseUrl || props.config?.cloudAuthBaseUrl || '');
|
|
1313
|
-
return String(preferredBase || '').trim().replace(/\/+$/, '');
|
|
1314
|
-
}, [props.config?.apiBaseUrl, props.config?.cloudAuthBaseUrl, runtimeMode]);
|
|
1315
|
-
const buildBillingApiUrl = useCallback((path) => {
|
|
1316
|
-
const normalizedPath = String(path || '').trim();
|
|
1317
|
-
if (!accountCapabilityApiBaseUrl)
|
|
1318
|
-
return normalizedPath;
|
|
1319
|
-
return `${accountCapabilityApiBaseUrl}${normalizedPath.startsWith('/') ? normalizedPath : `/${normalizedPath}`}`;
|
|
1320
|
-
}, [accountCapabilityApiBaseUrl]);
|
|
1321
1316
|
const connectedEnvironmentLabel = useMemo(() => resolveConnectedEnvironmentLabel(props.config?.cloudEnvironment, [
|
|
1322
1317
|
String(props.config?.cloudBaseUrl || ''),
|
|
1323
1318
|
String(props.config?.cloudAuthBaseUrl || ''),
|
|
@@ -1501,14 +1496,15 @@ export function StandaloneLayout(props) {
|
|
|
1501
1496
|
const workspaceId = String(teamManagementWorkspaceId || '').trim();
|
|
1502
1497
|
if (workspaceId)
|
|
1503
1498
|
headers['x-taskforce-workspace-id'] = workspaceId;
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
||
|
|
1507
|
-
||
|
|
1508
|
-
|
|
1499
|
+
const workspaceRole = teamWorkspaceRole || currentWorkspaceRole;
|
|
1500
|
+
if (workspaceRole === 'owner'
|
|
1501
|
+
|| workspaceRole === 'admin'
|
|
1502
|
+
|| workspaceRole === 'member'
|
|
1503
|
+
|| workspaceRole === 'read-only') {
|
|
1504
|
+
headers['x-taskforce-workspace-role'] = workspaceRole;
|
|
1509
1505
|
}
|
|
1510
1506
|
return headers;
|
|
1511
|
-
}, [currentWorkspaceRole, teamManagementWorkspaceId]);
|
|
1507
|
+
}, [currentWorkspaceRole, teamManagementWorkspaceId, teamWorkspaceRole]);
|
|
1512
1508
|
const startAccountSurfaceTiming = useCallback((surface) => {
|
|
1513
1509
|
const expectsBilling = isAuthenticated;
|
|
1514
1510
|
const expectsTeamManagement = canAccessCloudTeamManagement;
|
|
@@ -1544,59 +1540,117 @@ export function StandaloneLayout(props) {
|
|
|
1544
1540
|
surface: showAccountHub ? 'account_hub' : (showAccountMenu ? 'account_menu' : 'closed'),
|
|
1545
1541
|
durationMs: Math.round(getTimingNow() - startedAt),
|
|
1546
1542
|
teamManagementVisible: canOpenTeamManagement,
|
|
1547
|
-
billingPlanId: String(
|
|
1543
|
+
billingPlanId: String(accountProfileSummary?.planId || '').trim() || null
|
|
1548
1544
|
});
|
|
1549
1545
|
accountSurfaceOpenStartedAtRef.current = null;
|
|
1550
|
-
}, [
|
|
1551
|
-
const
|
|
1552
|
-
const
|
|
1553
|
-
const billingStatusUrl = buildBillingApiUrl(billingStatusPath);
|
|
1546
|
+
}, [accountProfileSummary?.planId, canOpenTeamManagement, showAccountHub, showAccountMenu]);
|
|
1547
|
+
const loadAccountProfileSummary = useCallback(async (options) => {
|
|
1548
|
+
const accountProfileSummaryUrl = resolveCloudAuthUrl(ACCOUNT_PROFILE_SUMMARY_PATH);
|
|
1554
1549
|
if (!isAuthenticated) {
|
|
1555
|
-
|
|
1550
|
+
setAccountProfileSummary(null);
|
|
1556
1551
|
setBillingError(null);
|
|
1557
|
-
|
|
1552
|
+
setTeamWorkspaceRole(null);
|
|
1553
|
+
setTeamPlanMode('unknown');
|
|
1554
|
+
setTeamManagementAccessLoading(false);
|
|
1555
|
+
setTeamManagementAccessError(null);
|
|
1556
|
+
invalidateAccountProfileSummaryCache(accountProfileSummaryUrl, { identityKey: authUserId });
|
|
1558
1557
|
markAccountSurfaceLoadSettled('billing');
|
|
1558
|
+
markAccountSurfaceLoadSettled('teamManagement');
|
|
1559
1559
|
return null;
|
|
1560
1560
|
}
|
|
1561
1561
|
const startedAt = getTimingNow();
|
|
1562
1562
|
setBillingLoading(true);
|
|
1563
1563
|
setBillingError(null);
|
|
1564
|
+
setTeamManagementAccessLoading(canAccessCloudTeamManagement);
|
|
1565
|
+
setTeamManagementAccessError(null);
|
|
1564
1566
|
try {
|
|
1565
|
-
const payload = await
|
|
1566
|
-
|
|
1567
|
-
|
|
1567
|
+
const payload = await loadAccountProfileSummaryCached(accountProfileSummaryUrl, {
|
|
1568
|
+
identityKey: authUserId,
|
|
1569
|
+
force: options?.force === true
|
|
1570
|
+
});
|
|
1571
|
+
const nextRole = payload?.workspaceRole === 'owner'
|
|
1572
|
+
|| payload?.workspaceRole === 'admin'
|
|
1573
|
+
|| payload?.workspaceRole === 'member'
|
|
1574
|
+
|| payload?.workspaceRole === 'read-only'
|
|
1575
|
+
? payload.workspaceRole
|
|
1576
|
+
: null;
|
|
1577
|
+
const nextMode = payload?.teamPlanMode === 'team' || payload?.teamPlanMode === 'personal'
|
|
1578
|
+
? payload.teamPlanMode
|
|
1579
|
+
: 'unknown';
|
|
1580
|
+
setAccountProfileSummary(payload);
|
|
1581
|
+
setTeamWorkspaceRole(nextRole);
|
|
1582
|
+
setTeamPlanMode(nextMode);
|
|
1583
|
+
setTeamManagementAccessError(null);
|
|
1584
|
+
logBootstrapDebug('account_profile_summary_resolved', {
|
|
1568
1585
|
durationMs: Math.round(getTimingNow() - startedAt),
|
|
1569
1586
|
planId: String(payload?.planId || '').trim() || null,
|
|
1570
|
-
gate: String(payload?.gate || '').trim() || null
|
|
1587
|
+
gate: String(payload?.gate || '').trim() || null,
|
|
1588
|
+
teamManagementAllowed: payload?.teamManagementAllowed === true
|
|
1571
1589
|
});
|
|
1572
1590
|
return payload;
|
|
1573
1591
|
}
|
|
1574
1592
|
catch (error) {
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1593
|
+
const message = error instanceof Error ? error.message : 'Failed to load account summary.';
|
|
1594
|
+
const hasPreviousSummary = Boolean(accountProfileSummaryRef.current);
|
|
1595
|
+
setBillingError(message);
|
|
1596
|
+
if (!hasPreviousSummary) {
|
|
1597
|
+
setTeamWorkspaceRole(null);
|
|
1598
|
+
setTeamPlanMode('unknown');
|
|
1599
|
+
setTeamManagementAccessError(message);
|
|
1600
|
+
}
|
|
1601
|
+
else {
|
|
1602
|
+
setTeamManagementAccessError(null);
|
|
1603
|
+
}
|
|
1604
|
+
logBootstrapDebug('account_profile_summary_failed', {
|
|
1578
1605
|
durationMs: Math.round(getTimingNow() - startedAt),
|
|
1579
|
-
error:
|
|
1606
|
+
error: message,
|
|
1607
|
+
preservedSummary: hasPreviousSummary
|
|
1580
1608
|
});
|
|
1581
|
-
return
|
|
1609
|
+
return accountProfileSummaryRef.current;
|
|
1582
1610
|
}
|
|
1583
1611
|
finally {
|
|
1584
1612
|
setBillingLoading(false);
|
|
1613
|
+
setTeamManagementAccessLoading(false);
|
|
1585
1614
|
markAccountSurfaceLoadSettled('billing');
|
|
1615
|
+
markAccountSurfaceLoadSettled('teamManagement');
|
|
1586
1616
|
}
|
|
1587
|
-
}, [
|
|
1617
|
+
}, [authUserId, canAccessCloudTeamManagement, isAuthenticated, markAccountSurfaceLoadSettled, resolveCloudAuthUrl]);
|
|
1618
|
+
const applyPlansAccountProfileSummary = useCallback((payload) => {
|
|
1619
|
+
setAccountProfileSummary(payload);
|
|
1620
|
+
const nextRole = payload?.workspaceRole === 'owner'
|
|
1621
|
+
|| payload?.workspaceRole === 'admin'
|
|
1622
|
+
|| payload?.workspaceRole === 'member'
|
|
1623
|
+
|| payload?.workspaceRole === 'read-only'
|
|
1624
|
+
? payload.workspaceRole
|
|
1625
|
+
: null;
|
|
1626
|
+
const nextMode = payload?.teamPlanMode === 'team' || payload?.teamPlanMode === 'personal'
|
|
1627
|
+
? payload.teamPlanMode
|
|
1628
|
+
: 'unknown';
|
|
1629
|
+
setTeamWorkspaceRole(nextRole);
|
|
1630
|
+
setTeamPlanMode(nextMode);
|
|
1631
|
+
}, []);
|
|
1632
|
+
const hasActiveCommercialEntitlement = useMemo(() => {
|
|
1633
|
+
const entitlementState = String(accountProfileSummary?.entitlementState || '').trim().toLowerCase();
|
|
1634
|
+
return ACTIVE_COMMERCIAL_STATES.has(entitlementState);
|
|
1635
|
+
}, [accountProfileSummary?.entitlementState]);
|
|
1588
1636
|
const handleStartCheckout = useCallback(async () => {
|
|
1589
1637
|
const params = new URLSearchParams();
|
|
1590
1638
|
params.set('screen', 'plans');
|
|
1591
1639
|
params.set('interval', billingIntervalChoice);
|
|
1640
|
+
const planId = String(accountProfileSummary?.planId || '').trim();
|
|
1641
|
+
const planVersionId = String(accountProfileSummary?.planVersionId || '').trim();
|
|
1642
|
+
if (planId)
|
|
1643
|
+
params.set('planId', planId);
|
|
1644
|
+
if (planVersionId)
|
|
1645
|
+
params.set('planVersionId', planVersionId);
|
|
1592
1646
|
navigate(`/?${params.toString()}`);
|
|
1593
|
-
}, [billingIntervalChoice, navigate]);
|
|
1647
|
+
}, [accountProfileSummary?.planId, accountProfileSummary?.planVersionId, billingIntervalChoice, navigate]);
|
|
1594
1648
|
const handleOpenBillingPortal = useCallback(async () => {
|
|
1595
1649
|
setBillingActionError(null);
|
|
1596
1650
|
setBillingNotice(null);
|
|
1597
1651
|
setBillingActionBusy(true);
|
|
1598
1652
|
try {
|
|
1599
|
-
const res = await fetch(
|
|
1653
|
+
const res = await fetch(resolveCloudAuthUrl('/api/taskforce/billing/portal-session'), {
|
|
1600
1654
|
method: 'POST',
|
|
1601
1655
|
credentials: 'include'
|
|
1602
1656
|
});
|
|
@@ -1618,18 +1672,18 @@ export function StandaloneLayout(props) {
|
|
|
1618
1672
|
finally {
|
|
1619
1673
|
setBillingActionBusy(false);
|
|
1620
1674
|
}
|
|
1621
|
-
}, [
|
|
1675
|
+
}, [resolveCloudAuthUrl]);
|
|
1622
1676
|
const handleSwitchSubscriptionInterval = useCallback(async () => {
|
|
1623
1677
|
setBillingActionError(null);
|
|
1624
1678
|
setBillingNotice(null);
|
|
1625
1679
|
setBillingActionBusy(true);
|
|
1626
1680
|
try {
|
|
1627
|
-
const currentPlanVersionId = String(
|
|
1681
|
+
const currentPlanVersionId = String(accountProfileSummary?.planVersionId || '').trim();
|
|
1628
1682
|
if (!currentPlanVersionId) {
|
|
1629
1683
|
setBillingActionError('No active plan version is linked to this account.');
|
|
1630
1684
|
return;
|
|
1631
1685
|
}
|
|
1632
|
-
const res = await fetch(
|
|
1686
|
+
const res = await fetch(resolveCloudAuthUrl('/api/taskforce/billing/subscription'), {
|
|
1633
1687
|
method: 'POST',
|
|
1634
1688
|
credentials: 'include',
|
|
1635
1689
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -1644,8 +1698,8 @@ export function StandaloneLayout(props) {
|
|
|
1644
1698
|
return;
|
|
1645
1699
|
}
|
|
1646
1700
|
setBillingNotice('Subscription updated.');
|
|
1647
|
-
|
|
1648
|
-
await
|
|
1701
|
+
invalidateAccountProfileSummaryCache(resolveCloudAuthUrl(ACCOUNT_PROFILE_SUMMARY_PATH), { identityKey: authUserId });
|
|
1702
|
+
await loadAccountProfileSummary();
|
|
1649
1703
|
}
|
|
1650
1704
|
catch {
|
|
1651
1705
|
setBillingActionError('Failed to update subscription interval.');
|
|
@@ -1653,94 +1707,17 @@ export function StandaloneLayout(props) {
|
|
|
1653
1707
|
finally {
|
|
1654
1708
|
setBillingActionBusy(false);
|
|
1655
1709
|
}
|
|
1656
|
-
}, [
|
|
1657
|
-
const loadTeamManagementAccess = useCallback(async () => {
|
|
1658
|
-
if (!canAccessCloudTeamManagement) {
|
|
1659
|
-
setTeamWorkspaceRole(null);
|
|
1660
|
-
setTeamPlanMode('unknown');
|
|
1661
|
-
setTeamManagementAccessLoading(false);
|
|
1662
|
-
setTeamManagementAccessError(null);
|
|
1663
|
-
markAccountSurfaceLoadSettled('teamManagement');
|
|
1664
|
-
return { role: null, teamPlanMode: 'unknown', allowed: false };
|
|
1665
|
-
}
|
|
1666
|
-
const startedAt = getTimingNow();
|
|
1667
|
-
setTeamManagementAccessLoading(true);
|
|
1668
|
-
setTeamManagementAccessError(null);
|
|
1669
|
-
try {
|
|
1670
|
-
const res = await fetchTaskforceApi('/api/taskforce/account/team-management-access', {
|
|
1671
|
-
method: 'GET',
|
|
1672
|
-
credentials: 'include',
|
|
1673
|
-
headers: teamAdminHeaders()
|
|
1674
|
-
}, accountCapabilityApiBaseUrl);
|
|
1675
|
-
const payload = await res.json().catch(() => ({}));
|
|
1676
|
-
if (!res.ok) {
|
|
1677
|
-
setTeamWorkspaceRole(null);
|
|
1678
|
-
setTeamPlanMode('unknown');
|
|
1679
|
-
setTeamManagementAccessError(String(payload?.error || 'Failed to load team management access.'));
|
|
1680
|
-
logBootstrapDebug('team_management_access_failed', {
|
|
1681
|
-
durationMs: Math.round(getTimingNow() - startedAt),
|
|
1682
|
-
status: res.status
|
|
1683
|
-
});
|
|
1684
|
-
return { role: null, teamPlanMode: 'unknown', allowed: false };
|
|
1685
|
-
}
|
|
1686
|
-
const nextRole = payload?.role === 'owner' || payload?.role === 'admin' || payload?.role === 'member' || payload?.role === 'read-only'
|
|
1687
|
-
? payload.role
|
|
1688
|
-
: null;
|
|
1689
|
-
const nextMode = payload?.teamPlanMode === 'team' || payload?.teamPlanMode === 'personal'
|
|
1690
|
-
? payload.teamPlanMode
|
|
1691
|
-
: 'unknown';
|
|
1692
|
-
const allowed = payload?.allowed === true;
|
|
1693
|
-
setTeamWorkspaceRole(nextRole);
|
|
1694
|
-
setTeamPlanMode(nextMode);
|
|
1695
|
-
setTeamManagementAccessError(null);
|
|
1696
|
-
logBootstrapDebug('team_management_access_loaded', {
|
|
1697
|
-
durationMs: Math.round(getTimingNow() - startedAt),
|
|
1698
|
-
role: nextRole,
|
|
1699
|
-
teamPlanMode: nextMode,
|
|
1700
|
-
allowed
|
|
1701
|
-
});
|
|
1702
|
-
return { role: nextRole, teamPlanMode: nextMode, allowed };
|
|
1703
|
-
}
|
|
1704
|
-
catch (error) {
|
|
1705
|
-
setTeamWorkspaceRole(null);
|
|
1706
|
-
setTeamPlanMode('unknown');
|
|
1707
|
-
setTeamManagementAccessError(error instanceof Error ? error.message : 'Failed to load team management access.');
|
|
1708
|
-
logBootstrapDebug('team_management_access_failed', {
|
|
1709
|
-
durationMs: Math.round(getTimingNow() - startedAt),
|
|
1710
|
-
error: error instanceof Error ? error.message : 'Failed to load team management access.'
|
|
1711
|
-
});
|
|
1712
|
-
return { role: null, teamPlanMode: 'unknown', allowed: false };
|
|
1713
|
-
}
|
|
1714
|
-
finally {
|
|
1715
|
-
setTeamManagementAccessLoading(false);
|
|
1716
|
-
markAccountSurfaceLoadSettled('teamManagement');
|
|
1717
|
-
}
|
|
1718
|
-
}, [accountCapabilityApiBaseUrl, canAccessCloudTeamManagement, markAccountSurfaceLoadSettled, teamAdminHeaders]);
|
|
1719
|
-
useEffect(() => {
|
|
1720
|
-
if (!showAccountMenu && !showTeamManagementModal && !showAccountHub)
|
|
1721
|
-
return;
|
|
1722
|
-
void loadTeamManagementAccess();
|
|
1723
|
-
}, [showAccountHub, showAccountMenu, showTeamManagementModal, loadTeamManagementAccess]);
|
|
1710
|
+
}, [accountProfileSummary?.planVersionId, authUserId, billingIntervalChoice, loadAccountProfileSummary, resolveCloudAuthUrl]);
|
|
1724
1711
|
useEffect(() => {
|
|
1725
1712
|
if (!isAuthenticated || !authSessionResolved)
|
|
1726
1713
|
return;
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
setTeamPlanMode('unknown');
|
|
1730
|
-
return;
|
|
1731
|
-
}
|
|
1732
|
-
void loadTeamManagementAccess();
|
|
1733
|
-
}, [authSessionResolved, canAccessCloudTeamManagement, isAuthenticated, loadTeamManagementAccess]);
|
|
1734
|
-
useEffect(() => {
|
|
1735
|
-
if (!isAuthenticated || !authSessionResolved)
|
|
1736
|
-
return;
|
|
1737
|
-
void loadBillingStatus();
|
|
1738
|
-
}, [authSessionResolved, isAuthenticated, loadBillingStatus]);
|
|
1714
|
+
void loadAccountProfileSummary();
|
|
1715
|
+
}, [authSessionResolved, isAuthenticated, loadAccountProfileSummary]);
|
|
1739
1716
|
useEffect(() => {
|
|
1740
1717
|
if (!showAccountHub && !showAccountMenu)
|
|
1741
1718
|
return;
|
|
1742
|
-
void
|
|
1743
|
-
}, [
|
|
1719
|
+
void loadAccountProfileSummary();
|
|
1720
|
+
}, [loadAccountProfileSummary, showAccountHub, showAccountMenu]);
|
|
1744
1721
|
const loadTeamUsers = useCallback(async () => {
|
|
1745
1722
|
if (!canManageTeamWorkspace)
|
|
1746
1723
|
return;
|
|
@@ -1843,6 +1820,47 @@ export function StandaloneLayout(props) {
|
|
|
1843
1820
|
}
|
|
1844
1821
|
navigate(`/setup?${params.toString()}`, { replace: true });
|
|
1845
1822
|
}, [navigate]);
|
|
1823
|
+
const handlePlansBack = useCallback(async () => {
|
|
1824
|
+
if (plansNavigationBusy)
|
|
1825
|
+
return;
|
|
1826
|
+
if (!isAuthenticated) {
|
|
1827
|
+
closePlansScreen();
|
|
1828
|
+
return;
|
|
1829
|
+
}
|
|
1830
|
+
const summary = await loadAccountProfileSummary({ force: true });
|
|
1831
|
+
const entitlementState = String(summary?.entitlementState || '').trim().toLowerCase();
|
|
1832
|
+
if (!ACTIVE_COMMERCIAL_STATES.has(entitlementState)) {
|
|
1833
|
+
return;
|
|
1834
|
+
}
|
|
1835
|
+
setPlansNavigationBusy(true);
|
|
1836
|
+
try {
|
|
1837
|
+
const result = await props.continueAfterCommercialOnboarding();
|
|
1838
|
+
if (!result.success) {
|
|
1839
|
+
pushNotice(result.error || 'Unable to finish onboarding.', 'error');
|
|
1840
|
+
if (result.destination === 'login') {
|
|
1841
|
+
navigate('/login', { replace: true });
|
|
1842
|
+
}
|
|
1843
|
+
return;
|
|
1844
|
+
}
|
|
1845
|
+
if (result.destination === 'setup') {
|
|
1846
|
+
openWorkspaceSetup();
|
|
1847
|
+
return;
|
|
1848
|
+
}
|
|
1849
|
+
closePlansScreen();
|
|
1850
|
+
}
|
|
1851
|
+
finally {
|
|
1852
|
+
setPlansNavigationBusy(false);
|
|
1853
|
+
}
|
|
1854
|
+
}, [
|
|
1855
|
+
closePlansScreen,
|
|
1856
|
+
isAuthenticated,
|
|
1857
|
+
loadAccountProfileSummary,
|
|
1858
|
+
navigate,
|
|
1859
|
+
openWorkspaceSetup,
|
|
1860
|
+
plansNavigationBusy,
|
|
1861
|
+
props,
|
|
1862
|
+
pushNotice
|
|
1863
|
+
]);
|
|
1846
1864
|
const handleSwitchWorkspace = useCallback(async (workspaceId) => {
|
|
1847
1865
|
if (!workspaceId || workspaceActionBusy)
|
|
1848
1866
|
return;
|
|
@@ -1869,12 +1887,12 @@ export function StandaloneLayout(props) {
|
|
|
1869
1887
|
setShowAccountMenu(false);
|
|
1870
1888
|
setShowTeamManagementModal(true);
|
|
1871
1889
|
setTeamManagementTab('members');
|
|
1872
|
-
const
|
|
1873
|
-
if (!
|
|
1890
|
+
const summary = await loadAccountProfileSummary();
|
|
1891
|
+
if (!(summary?.teamManagementAllowed ?? canOpenTeamManagement))
|
|
1874
1892
|
return;
|
|
1875
1893
|
await loadTeamUsers();
|
|
1876
1894
|
await loadTeamAuditPage(0);
|
|
1877
|
-
}, [
|
|
1895
|
+
}, [canOpenTeamManagement, loadAccountProfileSummary, loadTeamAuditPage, loadTeamUsers]);
|
|
1878
1896
|
const executeTeamUserAction = useCallback(async (userId, fn) => {
|
|
1879
1897
|
setTeamMgmtError(null);
|
|
1880
1898
|
setTeamActionBusyUserId(userId);
|
|
@@ -2544,7 +2562,7 @@ export function StandaloneLayout(props) {
|
|
|
2544
2562
|
}, [groupBy, activeCategories, activeTypes, priorities, approaches, assigneeOptions, scheduleColumns]);
|
|
2545
2563
|
// === SECTION: AccountMenuControl ===
|
|
2546
2564
|
// Not extracted: ~25 distinct props from local state would be needed.
|
|
2547
|
-
// References: isAuthenticated, authIdentityLabel,
|
|
2565
|
+
// References: isAuthenticated, authIdentityLabel, accountProfileSummary, runtimeLabel,
|
|
2548
2566
|
// connectedEnvironmentLabel, canManageCloudWorkspaces, workspaceActionBusy,
|
|
2549
2567
|
// setWorkspacePanelOpen, canOpenTeamManagement, openTeamManagementModal, and more.
|
|
2550
2568
|
const accountMenuControl = (_jsxs("div", { className: accountStyles.accountMenuWrap, ref: accountMenuRef, children: [_jsx("button", { className: `tf-control-icon ${accountStyles.avatarBtn}`, onClick: () => {
|
|
@@ -2559,7 +2577,7 @@ export function StandaloneLayout(props) {
|
|
|
2559
2577
|
}
|
|
2560
2578
|
return next;
|
|
2561
2579
|
});
|
|
2562
|
-
}, title: isAuthenticated ? 'Account' : 'Account (Not signed in)', "aria-label": isAuthenticated ? 'Account' : 'Account (Not signed in)', "aria-haspopup": "menu", "aria-expanded": showAccountMenu, children: _jsx("span", { className: accountStyles.avatarBadge, "aria-hidden": "true", children:
|
|
2580
|
+
}, title: isAuthenticated ? 'Account' : 'Account (Not signed in)', "aria-label": isAuthenticated ? 'Account' : 'Account (Not signed in)', "aria-haspopup": "menu", "aria-expanded": showAccountMenu, children: _jsx("span", { className: accountStyles.avatarBadge, "aria-hidden": "true", children: shouldShowResolvedAccountAvatar ? (_jsx("img", { src: accountAvatarUrl, alt: "", className: accountStyles.avatarImage })) : accountBadgeInitial ? (accountBadgeInitial) : (_jsx(User, { size: 14, className: accountStyles.avatarIcon })) }) }), showAccountMenu && (_jsxs("div", { className: accountStyles.accountMenu, role: "menu", "aria-label": "Account menu", children: [_jsxs("div", { className: accountStyles.accountMenuSection, children: [_jsx("div", { className: accountStyles.accountMenuSectionLabel, children: "Account" }), _jsx("div", { className: accountStyles.accountMenuHint, children: isAuthBootstrapPending
|
|
2563
2581
|
? 'Checking sign-in status...'
|
|
2564
2582
|
: isAuthenticated
|
|
2565
2583
|
? (_jsx(_Fragment, { children: hasAuthIdentity
|
|
@@ -2590,6 +2608,9 @@ export function StandaloneLayout(props) {
|
|
|
2590
2608
|
}, role: "menuitem", children: [_jsx(User, { size: 15 }), "Sign In / Register"] })), isAuthenticated && (_jsxs("button", { className: accountStyles.accountMenuItem, onClick: async () => {
|
|
2591
2609
|
setShowAccountMenu(false);
|
|
2592
2610
|
await logout();
|
|
2611
|
+
if (runtimeMode === 'cloud') {
|
|
2612
|
+
navigate('/login', { replace: true });
|
|
2613
|
+
}
|
|
2593
2614
|
}, role: "menuitem", children: [_jsx(LogOut, { size: 15 }), "Sign Out"] }))] }))] }));
|
|
2594
2615
|
const cycleEmptyColumnVisibility = useCallback(() => {
|
|
2595
2616
|
setEmptyColumnMode((prev) => {
|
|
@@ -3213,7 +3234,7 @@ export function StandaloneLayout(props) {
|
|
|
3213
3234
|
const workspacePrimaryAction = workspaceChromeDefinition.primaryAction
|
|
3214
3235
|
? primaryActionRegistry[workspaceChromeDefinition.primaryAction]
|
|
3215
3236
|
: null;
|
|
3216
|
-
return (_jsxs("div", { className: `${shellStyles.standaloneWrapper} ${zenMode ? styles.zenModeEnabled : ''}`, "data-theme": currentTheme, children: [_jsx(AppShellHeader, { projectName: projectName, currentWorkspaceId: currentWorkspaceId, runtimeMode: runtimeMode, theme: currentTheme, meta: isPlansScreen ? null : (_jsxs(_Fragment, { children: [_jsx("span", { className: styles.taskCountBadge, title: activeCountTitle, children: activeCountLabel }), normalizedAuthUserId && normalizedAuthUserId !== 'anonymous' && (_jsxs(_Fragment, { children: [_jsxs("span", { className: styles.taskCountBadge, title: "
|
|
3237
|
+
return (_jsxs("div", { className: `${shellStyles.standaloneWrapper} ${zenMode ? styles.zenModeEnabled : ''}`, "data-theme": currentTheme, children: [_jsx(AppShellHeader, { projectName: projectName, currentWorkspaceId: currentWorkspaceId, runtimeMode: runtimeMode, theme: currentTheme, meta: isPlansScreen ? null : (_jsxs(_Fragment, { children: [_jsx("span", { className: styles.taskCountBadge, title: activeCountTitle, children: activeCountLabel }), normalizedAuthUserId && normalizedAuthUserId !== 'anonymous' && (_jsxs(_Fragment, { children: [_jsxs("span", { className: styles.taskCountBadge, title: "Tasks assigned to me", children: [_jsx(User, { size: 13, className: styles.taskCountBadgeIcon, "aria-hidden": "true" }), assignedTaskCount] }), _jsxs("span", { className: `${styles.taskCountBadge} ${assignedOverdueTaskCount > 0 ? styles.taskCountBadgeAlert : ''}`.trim(), title: "Tasks overdue", children: [_jsx(ClockAlert, { size: 13, className: styles.taskCountBadgeIcon, "aria-hidden": "true" }), assignedOverdueTaskCount] })] })), shouldShowSyncStatus && (_jsx("button", { className: "tf-control-icon", onClick: () => setShowSyncStatusModal(true), title: `Sync manager: ${syncStatusMeta.label} | Last success: ${formattedLastSyncTime}`, style: {
|
|
3217
3238
|
marginLeft: '6px',
|
|
3218
3239
|
height: '24px',
|
|
3219
3240
|
width: '24px',
|
|
@@ -3225,7 +3246,7 @@ export function StandaloneLayout(props) {
|
|
|
3225
3246
|
display: 'inline-flex',
|
|
3226
3247
|
alignItems: 'center',
|
|
3227
3248
|
justifyContent: 'center'
|
|
3228
|
-
}, children: syncStatusMeta.icon === 'off' ? (_jsx(CloudOff, { size: 16 })) : (_jsx(Cloud, { size: 16 })) }))] })), actions: (_jsxs(_Fragment, { children: [isPlansScreen && (_jsx("button", { className: "tf-control-icon", onClick: handlePlansBack, title:
|
|
3249
|
+
}, children: syncStatusMeta.icon === 'off' ? (_jsx(CloudOff, { size: 16 })) : (_jsx(Cloud, { size: 16 })) }))] })), actions: (_jsxs(_Fragment, { children: [isPlansScreen && (_jsx("button", { className: "tf-control-icon", onClick: () => { void handlePlansBack(); }, title: isAuthenticated && !hasActiveCommercialEntitlement ? 'Choose a plan to continue.' : 'Continue to Taskforce', disabled: plansNavigationBusy || (isAuthenticated && !hasActiveCommercialEntitlement), children: hasActiveCommercialEntitlement ? 'Take Me to Taskforce' : 'Back' })), !isPlansScreen && (_jsxs(_Fragment, { children: [workspaceHeaderSections, workspacePrimaryAction] })), !isPlansScreen && _jsx(WorkspaceHeaderActions, { actions: universalDisplayActions }), !isPlansScreen && _jsx(WorkspaceHeaderActions, { actions: universalFilterActions }), accountMenuControl] })) }), _jsx(TopNoticeLayer, { notice: uiNotice, onDismiss: clearNotice }), authBlocked && (_jsx("div", { className: authStyles.authBlockedBanner, children: "Authentication required for this environment. Use the Account menu to sign in." })), !isPlansScreen && showFilters && workspaceFilterBar, isPlansScreen ? (_jsx("div", { className: `${shellStyles.standalonePage} ${shellStyles.standaloneContent} ${styles.appScrollbar} tf-scrollbar`, style: { position: 'relative', display: 'flex', flex: 1, minHeight: 0, overflowY: 'auto', overflowX: 'hidden', scrollbarGutter: 'stable' }, children: _jsx(Suspense, { fallback: _jsx("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'center', flex: 1 }, children: _jsx(Loader2, { size: 20, className: styles.spinner }) }), children: _jsx(PlansPage, { ...props, currentTheme: currentTheme, projectName: projectName, currentWorkspaceId: currentWorkspaceId, authUserId: authUserId, apiBaseUrl: apiBaseUrl, connectedEnvironmentSource: props.config?.cloudAuthBaseUrl || props.config?.apiBaseUrl || '', resolveCloudAuthUrl: resolveCloudAuthUrl, embedded: true, shellOwnsScroll: true, onAccountProfileSummaryChange: applyPlansAccountProfileSummary, onContinueToTaskforce: handlePlansBack, continueBusy: plansNavigationBusy }) }) })) : resolvedWorkspaceModule === 'docs' && documentsWorkspaceEnabled ? (_jsxs("div", { className: `${shellStyles.standalonePage} ${shellStyles.standaloneContent}`, style: { position: 'relative', display: 'flex', flex: 1, minHeight: 0, overflow: 'hidden', paddingLeft: `${WORKSPACE_TOOL_RAIL_WIDTH}px` }, children: [workspaceToolRail, _jsx(Suspense, { fallback: _jsx("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'center', flex: 1 }, children: _jsx(Loader2, { size: 20, className: styles.spinner }) }), children: _jsx(DocumentWorkspaceShell, { tasks: tasks, runtimeMode: runtimeMode, apiBaseUrl: props.config?.apiBaseUrl || '', cloudAuthBaseUrl: props.config?.cloudAuthBaseUrl || '', typeFilters: documentTypeFilters, attachmentFilters: documentAttachmentFilters, onTypeFiltersChange: setDocumentTypeFilters, onAttachmentFiltersChange: setDocumentAttachmentFilters, requestedDocPath: requestedDocPath, requestedDocAssetId: requestedDocAssetId, onRequestedDocHandled: () => {
|
|
3229
3250
|
setRequestedDocPath(null);
|
|
3230
3251
|
setRequestedDocAssetId(null);
|
|
3231
3252
|
}, enableTaskGeneration: true }) })] })) : resolvedWorkspaceModule === 'annotate' && annotatedAttachmentsWorkspaceEnabled ? (_jsxs("div", { className: `${shellStyles.standalonePage} ${shellStyles.standaloneContent}`, style: { position: 'relative', display: 'flex', flex: 1, minHeight: 0, overflow: 'hidden', paddingLeft: `${WORKSPACE_TOOL_RAIL_WIDTH}px` }, children: [workspaceToolRail, _jsx(Suspense, { fallback: _jsx("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'center', flex: 1 }, children: _jsx(Loader2, { size: 20, className: styles.spinner }) }), children: _jsx(AnnotatedAttachmentWorkspaceShell, { runtimeMode: runtimeMode, apiBaseUrl: props.config?.apiBaseUrl || '', cloudAuthBaseUrl: props.config?.cloudAuthBaseUrl || '', workspaceId: currentWorkspaceId, sessionLoadReady: annotatedWorkspaceReady, requestedTarget: requestedAnnotatedTarget, requestedSessionId: requestedAnnotatedSessionId, requestedOpenVersion: requestedAnnotatedOpenVersion, resolveTaskReferenceLabel: resolveAnnotatedTaskReferenceLabel, resolveImageReferenceLabel: resolveAnnotatedImageReferenceLabel, onOpenTarget: handleAnnotatedAttachmentOpenTarget, onContextChange: handleAnnotatedAttachmentContextChange, onBackToTask: handleBackToTaskFromAnnotatedAttachment }) })] })) : resolvedWorkspaceModule === 'workflows' ? (_jsxs("div", { className: `${shellStyles.standalonePage} ${shellStyles.standaloneContent}`, style: { position: 'relative', display: 'flex', flex: 1, minHeight: 0, overflow: 'hidden', paddingLeft: `${WORKSPACE_TOOL_RAIL_WIDTH}px` }, children: [workspaceToolRail, _jsx(Suspense, { fallback: _jsx("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'center', flex: 1 }, children: _jsx(Loader2, { size: 20, className: styles.spinner }) }), children: _jsx(WorkflowsModule, { availableWorkflows: availableWorkflows, availableEnvironments: availableEnvironments, exportEnvironment: exportEnvironment, exportWorkflowsPath: props.exportWorkflowsPath, exportingResource: exportingResource, exportResult: exportResult, onExportEnvironmentChange: props.setExportEnvironment, onExportWorkflows: onExportWorkflows, onRefreshWorkflows: fetchWorkflows, onFetchWorkflowTemplate: props.fetchWorkflowTemplate, onFetchWorkflowOverrideNames: props.fetchWorkflowOverrideNames, onSaveWorkflowTemplateDraft: props.saveWorkflowTemplateDraft, onResetWorkflowTemplateDraft: props.resetWorkflowTemplateDraft }) })] })) : resolvedWorkspaceModule === 'agents' ? (_jsxs("div", { className: `${shellStyles.standalonePage} ${shellStyles.standaloneContent}`, style: { position: 'relative', display: 'flex', flex: 1, minHeight: 0, overflow: 'hidden', paddingLeft: `${WORKSPACE_TOOL_RAIL_WIDTH}px` }, children: [workspaceToolRail, _jsx(Suspense, { fallback: _jsx("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'center', flex: 1 }, children: _jsx(Loader2, { size: 20, className: styles.spinner }) }), children: _jsx(AgentsModule, { workspaceId: currentWorkspaceId }) })] })) : (_jsxs("div", { className: `${shellStyles.standalonePage} ${shellStyles.standaloneContent} `, style: {
|
|
@@ -3244,7 +3265,7 @@ export function StandaloneLayout(props) {
|
|
|
3244
3265
|
inset: 0,
|
|
3245
3266
|
zIndex: 35,
|
|
3246
3267
|
pointerEvents: 'none',
|
|
3247
|
-
} }), _jsxs("div", { style: { position: 'relative', width: '100%', minWidth: 0, flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column', overflow: 'hidden' }, children: [props.loadingTasks && boardVisibleTasks.length > 0 && (_jsx("div", { className: styles.boardRefreshIndicator, "aria-live": "polite", "aria-label": "Refreshing tasks", children: _jsx(Loader2, { size: 14, className: styles.spinner }) })), _jsx(TaskKanban, { tasks: scopedBoardVisibleTasks, allTasks:
|
|
3268
|
+
} }), _jsxs("div", { style: { position: 'relative', width: '100%', minWidth: 0, flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column', overflow: 'hidden' }, children: [props.loadingTasks && boardVisibleTasks.length > 0 && (_jsx("div", { className: styles.boardRefreshIndicator, "aria-live": "polite", "aria-label": "Refreshing tasks", children: _jsx(Loader2, { size: 14, className: styles.spinner }) })), _jsx(TaskKanban, { tasks: scopedBoardVisibleTasks, allTasks: scopedKanbanAllTasks, columns: kanbanColumns, groupBy: groupBy, scheduleDates: scheduleDates, searchQuery: searchQuery, filterCategories: filterCategories, filterTypes: filterTypes, filterPriorities: filterPriorities, filterStatus: filterStatus, filterAssignees: filterAssignees, assigneeOptions: assigneeOptions, scheduleFilteredTaskIds: Array.from(scheduleFilteredTaskIds), copiedId: copiedId, taxonomies: taxonomies, types: activeTypes, priorities: priorities, onUpdateTask: handleUpdateTask, onTaskClick: (task) => handleEdit(task), onOpenTaskById: handleOpenTaskById, onCopyId: handleCopyId, onToggleInProgress: handleToggleInProgress, onToggleReview: handleToggleReview, onToggleComplete: handleToggleComplete, onToggleCancel: handleToggleCancel, onSetStatus: handleSetStatus, onArchiveTask: handleArchiveTask, onAddTaskToColumn: handleAddTaskToColumn, showTaskCardStatusLabel: showTaskCardStatusLabel, onScheduleDaySelected: (dateOnly) => {
|
|
3248
3269
|
setScheduleSelectedDate(dateOnly);
|
|
3249
3270
|
const parsed = parseDateOnlyLocal(dateOnly);
|
|
3250
3271
|
if (parsed) {
|
|
@@ -3285,7 +3306,16 @@ export function StandaloneLayout(props) {
|
|
|
3285
3306
|
top: '10px',
|
|
3286
3307
|
right: '10px',
|
|
3287
3308
|
zIndex: 20,
|
|
3288
|
-
}, children: _jsx(ChevronLeft, { size: 16 }) }))] }), groupBy === 'schedule' && (_jsx(ScheduleSidebar, { open: scheduleSidebarOpen, onClose: () => setScheduleSidebarOpen(false), scheduleSelectedDate: scheduleSelectedDate, setScheduleSelectedDate: setScheduleSelectedDate, scheduleCalendarMonth: scheduleCalendarMonth, setScheduleCalendarMonth: setScheduleCalendarMonth, scheduleShowWeekends: scheduleShowWeekends, setScheduleShowWeekends: setScheduleShowWeekends, scheduleShowBacklog: scheduleShowBacklog, setScheduleShowBacklog: setScheduleShowBacklog, scheduleOnlyExpired: scheduleOnlyExpired, setScheduleOnlyExpired: setScheduleOnlyExpired, expiredScheduledCount: expiredScheduledCount, overdueDueCount: overdueDueCount, expiredLeafCandidates: expiredLeafCandidates, expiredRecoveryCandidates: expiredRecoveryCandidates, onMoveExpiredToSelectedWeek: handleMoveExpiredToSelectedWeek, onMoveExpiredToBacklog: handleMoveExpiredToBacklog, scheduleBulkBusy: scheduleBulkBusy, globalWeekStartsOn: globalWeekStartsOn, resolvedLocale: resolvedLocale, todayDateOnly: todayDateOnly, scheduleBaseTasks: scheduleBaseTasks, scheduleWeekStart: scheduleWeekStart, scheduleWeekLabel: scheduleWeekLabel }))] })), _jsxs(Modal, { isOpen: activeTab === 'add', onClose: handleCloseModal, title: editingTaskId ? (currentTask?.isDeleted ? 'Deleted Task' : 'Edit Task') : 'New Task', size: taskModalFullscreen ? 'full' : 'xl', theme: currentTheme, headerActions: (_jsx("button", { className: "tf-control-icon", onClick: () => setTaskModalFullscreen((value) => !value), title: taskModalFullscreen ? 'Exit full screen' : 'Enter full screen', "aria-label": taskModalFullscreen ? 'Exit full screen' : 'Enter full screen', children: taskModalFullscreen ? _jsx(Minimize2, { size: 18 }) : _jsx(Maximize2, { size: 18 }) })), draggable: !taskModalFullscreen, closeOnOverlayClick: false, children: [_jsx(TaskActionHeader, { editingTaskId: editingTaskId, loading: loading, autoSaveState: autoSaveState, title: title, currentTask: currentTask, currentTaskWorkstream: currentTaskWorkstream, currentTaskInitiative: currentTaskInitiative, workstreamInput: workstreamInput, onWorkstreamInputChange: setWorkstreamInput, onSetWorkstreamForCurrentTask: handleSetWorkstreamForCurrentTask, handleSubmit: handleSubmit, resetForm: resetForm, handleCopyId: handleCopyId, copiedId: copiedId, tasks: tasks, handleToggleInProgress: handleToggleInProgress, handleToggleReview: handleToggleReview, handleToggleComplete: handleToggleComplete, handleToggleCancel: handleToggleCancel, handleSetStatus: handleSetStatus, handleArchiveTask: handleArchiveTask,
|
|
3309
|
+
}, children: _jsx(ChevronLeft, { size: 16 }) }))] }), groupBy === 'schedule' && (_jsx(ScheduleSidebar, { open: scheduleSidebarOpen, onClose: () => setScheduleSidebarOpen(false), scheduleSelectedDate: scheduleSelectedDate, setScheduleSelectedDate: setScheduleSelectedDate, scheduleCalendarMonth: scheduleCalendarMonth, setScheduleCalendarMonth: setScheduleCalendarMonth, scheduleShowWeekends: scheduleShowWeekends, setScheduleShowWeekends: setScheduleShowWeekends, scheduleShowBacklog: scheduleShowBacklog, setScheduleShowBacklog: setScheduleShowBacklog, scheduleOnlyExpired: scheduleOnlyExpired, setScheduleOnlyExpired: setScheduleOnlyExpired, expiredScheduledCount: expiredScheduledCount, overdueDueCount: overdueDueCount, expiredLeafCandidates: expiredLeafCandidates, expiredRecoveryCandidates: expiredRecoveryCandidates, onMoveExpiredToSelectedWeek: handleMoveExpiredToSelectedWeek, onMoveExpiredToBacklog: handleMoveExpiredToBacklog, scheduleBulkBusy: scheduleBulkBusy, globalWeekStartsOn: globalWeekStartsOn, resolvedLocale: resolvedLocale, todayDateOnly: todayDateOnly, scheduleBaseTasks: scheduleBaseTasks, scheduleWeekStart: scheduleWeekStart, scheduleWeekLabel: scheduleWeekLabel }))] })), _jsxs(Modal, { isOpen: activeTab === 'add', onClose: handleCloseModal, title: editingTaskId ? (currentTask?.isDeleted ? 'Deleted Task' : 'Edit Task') : 'New Task', size: taskModalFullscreen ? 'full' : 'xl', theme: currentTheme, headerActions: (_jsx("button", { className: "tf-control-icon", onClick: () => setTaskModalFullscreen((value) => !value), title: taskModalFullscreen ? 'Exit full screen' : 'Enter full screen', "aria-label": taskModalFullscreen ? 'Exit full screen' : 'Enter full screen', children: taskModalFullscreen ? _jsx(Minimize2, { size: 18 }) : _jsx(Maximize2, { size: 18 }) })), draggable: !taskModalFullscreen, closeOnOverlayClick: false, children: [_jsx(TaskActionHeader, { editingTaskId: editingTaskId, loading: loading, autoSaveState: autoSaveState, title: title, currentTask: currentTask, currentTaskWorkstream: currentTaskWorkstream, currentTaskInitiative: currentTaskInitiative, workstreamInput: workstreamInput, onWorkstreamInputChange: setWorkstreamInput, onSetWorkstreamForCurrentTask: handleSetWorkstreamForCurrentTask, handleSubmit: handleSubmit, resetForm: resetForm, handleCopyId: handleCopyId, copiedId: copiedId, tasks: tasks, handleToggleInProgress: handleToggleInProgress, handleToggleReview: handleToggleReview, handleToggleComplete: handleToggleComplete, handleToggleCancel: handleToggleCancel, handleSetStatus: handleSetStatus, handleArchiveTask: handleArchiveTask, handleUnarchiveTask: (taskId) => {
|
|
3310
|
+
if (currentTask?.isDeleted) {
|
|
3311
|
+
const deletedRecord = deletedTaskRecordByTaskId.get(taskId);
|
|
3312
|
+
if (!deletedRecord)
|
|
3313
|
+
return;
|
|
3314
|
+
void handleRestoreDeletedTask(deletedRecord.id);
|
|
3315
|
+
return;
|
|
3316
|
+
}
|
|
3317
|
+
void handleUnarchive(taskId);
|
|
3318
|
+
}, handleRestoreDeletedTask: currentTask?.deletedRecordId
|
|
3289
3319
|
? (deletedRecordId) => {
|
|
3290
3320
|
void handleRestoreDeletedTask(deletedRecordId);
|
|
3291
3321
|
}
|
|
@@ -3298,7 +3328,7 @@ export function StandaloneLayout(props) {
|
|
|
3298
3328
|
resetForm();
|
|
3299
3329
|
setActiveTab('tasks');
|
|
3300
3330
|
}
|
|
3301
|
-
: undefined }), _jsx(TaskForm, { editingTaskId: editingTaskId, error: error, title: title, description: description, checklistItems: checklistItems, category: category, type: type, priority: priority, complexity: complexity, manualComplexityEnabled: manualComplexityEnabled, approach: approach, assignee: assignee, scheduledDate: scheduledDate, dueDate: dueDate, workstreamInput: workstreamInput, formTaxonomies: formTaxonomies, onTaxonomyChange: (id, val) => setFormTaxonomies(prev => ({ ...prev, [id]: val })), taxonomies: taxonomies, comments: comments, newCommentText: newCommentText, contextFiles: attachments, currentWorkspaceId: currentWorkspaceId, apiBaseUrl: apiBaseUrl, descriptionFocused: descriptionFocused, showMarkdownHelp: showMarkdownHelp, showChecklist: showChecklist, checklistEnabled: checklistDropdownEnabled, showComments: showComments, categories: activeCategories, types: activeTypes, priorities: priorities, taxonomyDisplayLabels: taxonomyDisplayLabels, assigneeOptions: assigneeOptions, workstreams: props.workstreams, copiedId: copiedId, onTitleChange: setTitle, onDescriptionChange: setDescription, onChecklistItemsChange: setChecklistItems, onCategoryChange: setCategory, onTypeChange: setType, onPriorityChange: setPriority, onComplexityChange: setComplexity, onApproachChange: (val) => { setApproach(val); setFormTaxonomies(prev => ({ ...prev, approach: val })); }, onAssigneeChange: setAssignee, onScheduledDateChange: setScheduledDate, onDueDateChange: setDueDate, onWorkstreamInputChange: setWorkstreamInput, onNewCommentTextChange: setNewCommentText, onDescriptionFocusedChange: setDescriptionFocused, onShowMarkdownHelpChange: setShowMarkdownHelp, onShowChecklistChange: setShowChecklist, onShowCommentsChange: setShowComments, onOpenSettings: (section) => {
|
|
3331
|
+
: undefined }), _jsx(TaskForm, { editingTaskId: editingTaskId, error: error, title: title, description: description, checklistItems: checklistItems, category: category, type: type, priority: priority, complexity: complexity, manualComplexityEnabled: manualComplexityEnabled, approach: approach, assignee: assignee, scheduledDate: scheduledDate, dueDate: dueDate, workstreamInput: workstreamInput, formTaxonomies: formTaxonomies, onTaxonomyChange: (id, val) => setFormTaxonomies(prev => ({ ...prev, [id]: val })), taxonomies: taxonomies, comments: comments, newCommentText: newCommentText, contextFiles: attachments, currentWorkspaceId: currentWorkspaceId, apiBaseUrl: apiBaseUrl, descriptionFocused: descriptionFocused, showMarkdownHelp: showMarkdownHelp, showChecklist: showChecklist, checklistEnabled: checklistDropdownEnabled, showComments: showComments, categories: activeCategories, types: activeTypes, priorities: priorities, taxonomyDisplayLabels: taxonomyDisplayLabels, assigneeOptions: assigneeOptions, workstreams: props.workstreams, initiatives: props.initiatives, copiedId: copiedId, onTitleChange: setTitle, onDescriptionChange: setDescription, onChecklistItemsChange: setChecklistItems, onCategoryChange: setCategory, onTypeChange: setType, onPriorityChange: setPriority, onComplexityChange: setComplexity, onApproachChange: (val) => { setApproach(val); setFormTaxonomies(prev => ({ ...prev, approach: val })); }, onAssigneeChange: setAssignee, onScheduledDateChange: setScheduledDate, onDueDateChange: setDueDate, onWorkstreamInputChange: setWorkstreamInput, onNewCommentTextChange: setNewCommentText, onDescriptionFocusedChange: setDescriptionFocused, onShowMarkdownHelpChange: setShowMarkdownHelp, onShowChecklistChange: setShowChecklist, onShowCommentsChange: setShowComments, onOpenSettings: (section) => {
|
|
3302
3332
|
setSettingsSection(section);
|
|
3303
3333
|
setActiveTab('settings');
|
|
3304
3334
|
}, onSubmit: handleSubmit, commentsEndRef: commentsEndRef, onAddComment: () => handleAddComment(newCommentText), onOpenTaskById: handleOpenTaskById, onAddContextFile: (file) => {
|
|
@@ -3350,11 +3380,11 @@ export function StandaloneLayout(props) {
|
|
|
3350
3380
|
setShowHelpModal(false);
|
|
3351
3381
|
setActiveTab('settings');
|
|
3352
3382
|
setSettingsSection('general');
|
|
3353
|
-
} }), _jsx(EditProfileModal, { isOpen: showEditProfileModal, theme: currentTheme, onClose: closeEditProfileModal, onSave: () => { void handleSaveProfile(); }, displayName: profileDisplayNameDraft, email: authEmailLabel, avatarDisplayUrl: profileAvatarDisplayUrl, accountBadgeInitial: accountBadgeInitial, avatarInputRef: profileAvatarInputRef, avatarAccept: PROFILE_AVATAR_ACCEPT, avatarDraftId: profileAvatarDraftId, saveBusy: profileSaveBusy, avatarBusy: profileAvatarBusy, saveError: profileSaveError, saveNotice: profileSaveNotice, onDisplayNameChange: setProfileDisplayNameDraft, onAvatarInputChange: (file) => { void handleProfileAvatarSelected(file); }, onStartAvatarUpload: () => profileAvatarInputRef.current?.click(), onDiscardUpload: handleDiscardPendingProfileAvatar, onRemovePhoto: handleRemoveProfileAvatar }), _jsx(AccountHubModal, { isOpen: showAccountHub, theme: currentTheme, runtimeMode: runtimeMode, authRequiredForApi: authRequiredForApi, isAuthenticated: isAuthenticated, hasAuthIdentity: hasAuthIdentity, authIdentityLabel: authIdentityLabel, billingLoading: billingLoading, billingError: billingError, billingActionError: billingActionError, billingNotice: billingNotice, billingActionBusy: billingActionBusy, billingIntervalChoice: billingIntervalChoice,
|
|
3383
|
+
} }), _jsx(EditProfileModal, { isOpen: showEditProfileModal, theme: currentTheme, onClose: closeEditProfileModal, onSave: () => { void handleSaveProfile(); }, displayName: profileDisplayNameDraft, email: authEmailLabel, avatarDisplayUrl: profileAvatarDisplayUrl, accountBadgeInitial: accountBadgeInitial, avatarInputRef: profileAvatarInputRef, avatarAccept: PROFILE_AVATAR_ACCEPT, avatarDraftId: profileAvatarDraftId, saveBusy: profileSaveBusy, avatarBusy: profileAvatarBusy, saveError: profileSaveError, saveNotice: profileSaveNotice, onDisplayNameChange: setProfileDisplayNameDraft, onAvatarInputChange: (file) => { void handleProfileAvatarSelected(file); }, onStartAvatarUpload: () => profileAvatarInputRef.current?.click(), onDiscardUpload: handleDiscardPendingProfileAvatar, onRemovePhoto: handleRemoveProfileAvatar }), _jsx(AccountHubModal, { isOpen: showAccountHub, theme: currentTheme, runtimeMode: runtimeMode, authRequiredForApi: authRequiredForApi, isAuthenticated: isAuthenticated, hasAuthIdentity: hasAuthIdentity, authIdentityLabel: authIdentityLabel, billingLoading: billingLoading, billingError: billingError, billingActionError: billingActionError, billingNotice: billingNotice, billingActionBusy: billingActionBusy, billingIntervalChoice: billingIntervalChoice, accountProfileSummary: accountProfileSummary, currentWorkspaceId: currentWorkspaceId, canOpenTeamManagement: canOpenTeamManagement, canManageWorkspaceSync: canManageWorkspaceSync, workspaceCloudSyncEnabled: workspaceCloudSyncEnabled, syncStatusLabel: syncStatusMeta.label, workspaceSyncError: workspaceSyncError, syncControlBusy: syncControlBusy, onClose: () => setShowAccountHub(false), onOpenWorkspaceAudit: () => {
|
|
3354
3384
|
setShowAccountHub(false);
|
|
3355
3385
|
void openTeamManagementModal();
|
|
3356
3386
|
setTeamManagementTab('audit');
|
|
3357
|
-
}, onBillingIntervalChange: setBillingIntervalChoice, onRefreshBilling: () => { void
|
|
3387
|
+
}, onBillingIntervalChange: setBillingIntervalChoice, onRefreshBilling: () => { void loadAccountProfileSummary(); }, onUpdateInterval: () => { void handleSwitchSubscriptionInterval(); }, onManageBilling: () => { void handleOpenBillingPortal(); }, onStartCheckout: () => { void handleStartCheckout(); }, onToggleWorkspaceSync: (enabled) => { void handleWorkspaceSyncToggle(enabled); }, onOpenHelp: () => {
|
|
3358
3388
|
setShowAccountHub(false);
|
|
3359
3389
|
setShowHelpModal(true);
|
|
3360
3390
|
} }), _jsx(TeamManagementModal, { isOpen: showTeamManagementModal, theme: currentTheme, teamPlanMode: teamPlanMode, teamMgmtError: teamMgmtError, teamManagementTab: teamManagementTab, teamUsersLoading: teamUsersLoading, teamUsers: teamUsers, teamActionBusyUserId: teamActionBusyUserId, teamInviteFeedback: teamInviteFeedback, teamInviteEmail: teamInviteEmail, teamInviteRole: teamInviteRole, teamInvitePermissionMode: teamInvitePermissionMode, teamInviteBusy: teamInviteBusy, pendingInvites: pendingInvites, teamAuditLoading: teamAuditLoading, teamAuditEvents: teamAuditEvents, teamAuditPage: teamAuditPage, teamAuditPages: teamAuditPages, teamAuditHasMore: teamAuditHasMore, onClose: () => setShowTeamManagementModal(false), onOpenMembersTab: () => {
|