@taskforcehq/taskforce 0.3.306 → 0.3.307
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/README.md +0 -2
- package/dist/Taskforce.module.css +317 -27
- package/dist/TaskforceCore.js +1 -0
- package/dist/TaskforceCore.test.js +178 -0
- package/dist/components/activity/EntityActivityTimeline.d.ts +34 -0
- package/dist/components/activity/EntityActivityTimeline.js +81 -0
- package/dist/components/context/ContextAttachmentManager.js +15 -3
- package/dist/components/features/AgentsModule.d.ts +5 -1
- package/dist/components/features/AgentsModule.js +142 -39
- package/dist/components/features/AgentsModule.test.js +260 -11
- package/dist/components/features/AnnotatedAttachmentWorkspace.d.ts +3 -1
- package/dist/components/features/AnnotatedAttachmentWorkspace.js +118 -4
- package/dist/components/features/AnnotatedAttachmentWorkspace.test.js +52 -0
- package/dist/components/features/DocumentIndex.d.ts +2 -2
- package/dist/components/features/DocumentIndex.js +3 -4
- package/dist/components/features/DocumentViewer.d.ts +3 -1
- package/dist/components/features/DocumentViewer.js +6 -5
- package/dist/components/features/DocumentWorkspace.d.ts +10 -2
- package/dist/components/features/DocumentWorkspace.js +15 -4
- package/dist/components/features/DocumentWorkspace.test.js +20 -3
- package/dist/components/features/TaskSettings.d.ts +2 -0
- package/dist/components/features/TaskSettings.js +83 -78
- package/dist/components/features/TaskSettings.test.js +171 -82
- package/dist/components/task/TaskActionHeader.js +11 -5
- package/dist/components/task/TaskActionHeader.test.js +10 -0
- package/dist/components/task/TaskCard.js +6 -2
- package/dist/components/task/TaskContextUpload.test.js +3 -3
- package/dist/components/task/TaskForm.js +14 -64
- package/dist/components/task/TaskKanban.js +0 -8
- package/dist/components/task/TaskList.js +5 -1
- package/dist/components/task/TaskList.test.js +4 -0
- package/dist/components/ui/HierarchyActionBadge.d.ts +10 -0
- package/dist/components/ui/HierarchyActionBadge.js +5 -0
- package/dist/components/views/AppShellHeader.d.ts +3 -1
- package/dist/components/views/AppShellHeader.js +27 -11
- package/dist/components/views/AppShellHeader.test.js +18 -1
- package/dist/components/views/PlanComparisonPage.js +9 -1
- package/dist/components/views/PlanComparisonPage.test.js +19 -0
- package/dist/components/views/PlansPage.js +1 -1
- package/dist/components/views/StandaloneLayout.js +256 -69
- package/dist/components/views/WidgetView.js +10 -8
- package/dist/components/views/panels/PlanningDrawer.d.ts +19 -6
- package/dist/components/views/panels/PlanningDrawer.js +259 -51
- package/dist/components/views/panels/PlanningDrawer.test.js +392 -4
- package/dist/config/envSchema.js +1 -0
- package/dist/core/AiProfileService.d.ts +7 -0
- package/dist/core/AiProfileService.js +460 -35
- package/dist/core/AiProfiles.test.js +648 -2
- package/dist/core/AttachmentLinkService.d.ts +3 -0
- package/dist/core/AttachmentLinkService.js +58 -13
- package/dist/core/GlobalSettingsService.js +12 -0
- package/dist/core/McpTokenService.d.ts +12 -0
- package/dist/core/McpTokenService.js +44 -1
- package/dist/core/PlanningEntities.test.js +366 -4
- package/dist/core/TaskActivityService.d.ts +28 -1
- package/dist/core/TaskActivityService.js +227 -46
- package/dist/core/TaskActivitySync.test.d.ts +1 -0
- package/dist/core/TaskActivitySync.test.js +90 -0
- package/dist/core/TaskAuditTimeline.test.js +96 -0
- package/dist/core/Taskforce.d.ts +190 -26
- package/dist/core/Taskforce.ids.test.js +58 -0
- package/dist/core/Taskforce.js +775 -71
- package/dist/core/Taskforce.mcpAuth.test.js +109 -0
- package/dist/core/types.d.ts +7 -0
- package/dist/hooks/auth/useTaskforceAuthBootstrap.js +2 -1
- package/dist/hooks/bootstrapTimeouts.d.ts +4 -0
- package/dist/hooks/bootstrapTimeouts.js +8 -0
- package/dist/hooks/bootstrapTimeouts.test.d.ts +1 -0
- package/dist/hooks/bootstrapTimeouts.test.js +12 -0
- package/dist/hooks/sync/orchestratorShared.d.ts +3 -3
- package/dist/hooks/sync/orchestratorShared.js +61 -1
- package/dist/hooks/sync/recovery.js +8 -0
- package/dist/hooks/sync/recovery.test.js +5 -5
- package/dist/hooks/sync/transfers.d.ts +2 -1
- package/dist/hooks/sync/transfers.js +36 -9
- package/dist/hooks/sync/transfers.test.js +534 -2
- package/dist/hooks/useFilterSort.js +13 -13
- package/dist/hooks/useFilterSort.test.js +87 -1
- package/dist/hooks/useSyncOrchestrator.js +50 -5
- package/dist/hooks/useTaskforce.d.ts +85 -50
- package/dist/hooks/useTaskforce.js +44 -14
- package/dist/hooks/useTaskforce.runtime-routing.test.js +94 -0
- package/dist/hooks/useTaskforce.sync-behavior.test.js +99 -0
- package/dist/hooks/useWorkspaceSyncController.js +7 -1
- package/dist/hooks/useWorkspaceSyncController.test.js +48 -0
- package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +14 -7
- package/dist/mcp/canonicalAssetHelpers.d.ts +16 -4
- package/dist/mcp/canonicalAssetHelpers.js +18 -10
- package/dist/mcp/canonicalAssetHelpers.test.d.ts +1 -0
- package/dist/mcp/canonicalAssetHelpers.test.js +67 -0
- package/dist/mcp/clientIntegrations.d.ts +1 -0
- package/dist/mcp/clientIntegrations.js +25 -0
- package/dist/mcp/clientIntegrations.test.js +14 -3
- package/dist/mcp/clientProfileDefaults.js +3 -3
- package/dist/mcp/collaborationRegistrar.js +7 -7
- package/dist/mcp/documentAssetRegistrar.js +113 -7
- package/dist/mcp/runtime.d.ts +1 -0
- package/dist/mcp/runtime.js +969 -122
- package/dist/mcp/runtime.test.js +1083 -11
- package/dist/mcp/taskAttachmentTypes.d.ts +1 -1
- package/dist/mcp/taskPlanningRegistrar.js +48 -0
- package/dist/mcp/toolRegistry.d.ts +56 -0
- package/dist/mcp/toolRegistry.js +8 -0
- package/dist/mcp/toolRegistry.test.js +4 -0
- package/dist/migrations/taskSchemaMigrations.js +21 -0
- package/dist/server/aiProfileAvatarAssets.d.ts +49 -0
- package/dist/server/aiProfileAvatarAssets.js +319 -0
- package/dist/server/aiProfileAvatarAssets.test.d.ts +1 -0
- package/dist/server/aiProfileAvatarAssets.test.js +213 -0
- package/dist/server/annotatedAttachmentsRoutes.test.js +66 -7
- package/dist/server/index.js +4 -0
- package/dist/server/index.test.js +6 -1
- package/dist/server/routes/admin.js +187 -9
- package/dist/server/routes/annotatedAttachments.js +51 -0
- package/dist/server/routes/auth.d.ts +11 -0
- package/dist/server/routes/auth.js +189 -27
- package/dist/server/routes/authSupport.d.ts +4 -0
- package/dist/server/routes/authSupport.js +12 -1
- package/dist/server/routes/billing.js +11 -0
- package/dist/server/routes/billing.test.js +3 -0
- package/dist/server/routes/documents.js +10 -0
- package/dist/server/routes/shared.js +0 -10
- package/dist/server/routes/sync.integration.test.js +221 -0
- package/dist/server/routes/sync.js +13 -3
- package/dist/server/routes/syncSnapshotRoutes.js +2 -0
- package/dist/server/routes/tasks.js +12 -9
- package/dist/server/routes.js +87 -8
- package/dist/server/routes.test.js +890 -22
- package/dist/shared/aiProfileSurfaceType.d.ts +1 -1
- package/dist/shared/aiProfileSurfaceType.js +10 -8
- package/dist/storage/objectStorage.d.ts +1 -0
- package/dist/storage/objectStorage.js +2 -1
- package/dist/storage/objectStorageClient.d.ts +1 -0
- package/dist/storage/objectStorageClient.js +41 -8
- package/dist/storage/objectStorageClient.test.js +26 -1
- package/dist/storage/objectStorageConfig.js +3 -1
- package/dist/storage/objectStorageConfig.test.js +13 -1
- package/dist/sync/collaborationSyncPayload.js +2 -0
- package/dist/sync/collaborationSyncPayload.test.js +1 -0
- package/dist/sync/collaborationSyncState.d.ts +3 -3
- package/dist/sync/collaborationSyncState.js +19 -12
- package/dist/sync/contentSyncPayload.d.ts +5 -1
- package/dist/sync/contentSyncPayload.js +9 -0
- package/dist/sync/contentSyncPayload.test.js +39 -0
- package/dist/sync/contentSyncState.d.ts +5 -1
- package/dist/sync/contentSyncState.js +231 -37
- package/dist/sync/planningSyncPayload.js +5 -0
- package/dist/sync/planningSyncPayload.test.js +24 -0
- package/dist/sync/syncApplyHandlers.d.ts +4 -4
- package/dist/sync/syncApplyHandlers.js +89 -31
- package/dist/sync/syncApplyHandlers.test.js +184 -4
- package/dist/sync/syncResourceAdapters.d.ts +2 -0
- package/dist/sync/syncResourceAdapters.js +2 -0
- package/dist/sync/syncService.d.ts +1 -0
- package/dist/sync/syncService.js +13 -1
- package/dist/sync/syncService.test.js +39 -0
- package/dist/sync/workspacePullFeed.d.ts +4 -0
- package/dist/sync/workspacePullFeed.js +129 -70
- package/dist/sync/workspacePullFeed.test.js +49 -0
- package/dist/sync/workspaceSyncModel.d.ts +28 -6
- package/dist/sync/workspaceSyncModel.js +159 -45
- package/dist/sync/workspaceSyncModel.test.js +269 -3
- package/dist/types.d.ts +33 -2
- package/dist/ui/assets/AgentsModule-2y82_3DO.js +1 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-BTLZZCiQ.js +3 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-BVKew-mH.css +1 -0
- package/dist/ui/assets/ContextAttachmentManager-D2epuNnG.js +3 -0
- package/dist/ui/assets/DocumentWorkspace-D4rJKXzd.css +1 -0
- package/dist/ui/assets/DocumentWorkspace-sVa-3Do6.js +252 -0
- package/dist/ui/assets/EntityActivityTimeline-DyqvvhuF.css +1 -0
- package/dist/ui/assets/EntityActivityTimeline-Zods27y_.js +1 -0
- package/dist/ui/assets/{InitiativesModule-9E6ParrY.js → InitiativesModule-D4XseTwW.js} +1 -1
- package/dist/ui/assets/PlansPage-D5AcbO0L.js +1 -0
- package/dist/ui/assets/PlansPage-Dvqsz5zc.css +1 -0
- package/dist/ui/assets/TaskContextUpload-uC5qx4Bv.js +1 -0
- package/dist/ui/assets/TaskSettings-CqvPAsTv.js +9 -0
- package/dist/ui/assets/{WorkflowsModule-BA7jcEpH.js → WorkflowsModule-oOA9bcdK.js} +4 -4
- package/dist/ui/assets/documentReferences-DPZuTgHh.js +1 -0
- package/dist/ui/assets/index-607WPo_X.js +4 -0
- package/dist/ui/assets/index-CYyodXsg.css +1 -0
- package/dist/ui/assets/{vendor-icons-DuEd_65c.js → vendor-icons-B32hGuF2.js} +1 -1
- package/dist/ui/index.html +3 -3
- package/dist/ui/product/agent manager.png +0 -0
- package/dist/ui/product/agent_manager_02.png +0 -0
- package/dist/utils/aiProfileEvents.d.ts +7 -0
- package/dist/utils/aiProfileEvents.js +6 -0
- package/dist/utils/assignees.d.ts +6 -0
- package/dist/utils/assignees.js +8 -1
- package/dist/utils/assignees.test.d.ts +1 -0
- package/dist/utils/assignees.test.js +25 -0
- package/dist/utils/avatarDisplay.d.ts +1 -0
- package/dist/utils/avatarDisplay.js +15 -0
- package/dist/utils/contextFiles.d.ts +3 -1
- package/dist/utils/contextFiles.js +2 -1
- package/dist/utils/taskActivity.d.ts +7 -1
- package/dist/utils/taskActivity.js +63 -1
- package/dist/utils/taskActivity.test.js +23 -1
- package/dist/utils/taskSearch.d.ts +22 -0
- package/dist/utils/taskSearch.js +87 -0
- package/dist/utils/taskSearch.test.d.ts +1 -0
- package/dist/utils/taskSearch.test.js +69 -0
- package/dist/utils/taskUtils.js +10 -3
- package/dist/utils/taskUtils.test.d.ts +1 -0
- package/dist/utils/taskUtils.test.js +19 -0
- package/package.json +1 -1
- package/dist/ui/assets/AgentsModule-DrLawwNl.js +0 -1
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-BaS2VwIr.css +0 -1
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-Z9_whf7F.js +0 -3
- package/dist/ui/assets/DocumentWorkspace-B03MaSkw.js +0 -252
- package/dist/ui/assets/DocumentWorkspace-Dhdso07p.css +0 -1
- package/dist/ui/assets/PlansPage-CvfnMiWq.css +0 -1
- package/dist/ui/assets/PlansPage-DRXscYxH.js +0 -1
- package/dist/ui/assets/TaskSettings-DZX4jk7e.js +0 -9
- package/dist/ui/assets/index-9eT8e0Lu.css +0 -1
- package/dist/ui/assets/index-C6k75jr8.js +0 -6
|
@@ -3,7 +3,7 @@ import React, { useEffect, useMemo, useState } from 'react';
|
|
|
3
3
|
import { Sun, Moon, Sparkles, Keyboard, FileText, Check, AlertTriangle, Loader2, Settings, Layers, Box, Copy, Trash2, Terminal, Bot, Codepen, Command, Wind, Github, Zap, ChevronDown, ChevronRight, Plug } from 'lucide-react';
|
|
4
4
|
import styles from '../../Taskforce.module.css';
|
|
5
5
|
import { TASKFORCE_THEME_OPTIONS } from '../../utils/theme';
|
|
6
|
-
import { MCP_CLIENT_OPTIONS, buildCloudMcpClientIntegration, buildLocalMcpClientIntegration, buildCloudMcpServerId, sanitizeMcpId } from '../../mcp/clientIntegrations';
|
|
6
|
+
import { MCP_CLIENT_OPTIONS, buildCloudMcpClientIntegration, buildLocalMcpClientIntegration, buildCloudMcpServerId, buildLocalAiProfileEnv, sanitizeMcpId } from '../../mcp/clientIntegrations';
|
|
7
7
|
import { resolveTaskforceMcpBaseUrlFromBaseUrl } from '../../config/cloudEnvironment';
|
|
8
8
|
import { TaxonomyManager } from './settings/TaxonomyManager';
|
|
9
9
|
const THEME_ICON_MAP = {
|
|
@@ -14,8 +14,9 @@ const THEME_ICON_MAP = {
|
|
|
14
14
|
};
|
|
15
15
|
const DEFAULT_MCP_TOKEN_SCOPES = ['tasks:read', 'tasks:write', 'workspace:read'];
|
|
16
16
|
export function TaskSettings(props) {
|
|
17
|
-
const { settingsModel, onSectionChange } = props;
|
|
18
|
-
const
|
|
17
|
+
const { settingsModel, onSectionChange, renderMode = 'full' } = props;
|
|
18
|
+
const isMcpOnly = renderMode === 'mcp-only';
|
|
19
|
+
const { currentTheme, globalTheme, themeUseGlobalDefault, keyShortcut, jsonBackupEnabled, globalJsonBackupEnabled, globalWeekStartsOn, locale = 'en-US', supportedLocales = ['en-US', 'es-419', 'pt-BR'], jsonBackupUseGlobalDefault, manualComplexityEnabled, checklistDropdownEnabled = true, showTaskCardStatusLabel = true, exportWorkflowsPath, exportingResource, exportResult, initialSection, onThemeChange, onSaveTheme, onSaveGlobalTheme, onResetProjectToGlobal, onKeyShortcutChange, onJsonBackupEnabledChange, onSaveGlobalJsonBackupEnabled, onSaveGlobalWeekStartsOn, onSaveLocale, onManualComplexityEnabledChange, onChecklistDropdownEnabledChange, onShowTaskCardStatusLabelChange, onSaveSettings, onExportWorkflowsPathChange, onShowFolderBrowserChange, onBrowserTargetChange, onFetchFolders, categories, pathValidation, taxonomyDisplayLabels, onUpdateCategory, onRemoveCategory, onSaveCategory, onAddPath, onRemovePath, onUpdateCategoryIcon, onUpdateCategoryColor, types, onSaveType, onRemoveType, onUpdateType, taxonomies, onUpdateTaxonomies, priorities, onUpdatePriorities, onAnalyzeSystemTaxonomyPack, onApplySystemTaxonomyPack, onUpdateTaxonomyDisplayLabels, projectRoot, projectName, mcpHostRoot, serverHostRoot, mcpScriptPath, tenantId, workspaceId, runtimeMode = 'local', cloudAuthBaseUrl = '', cloudMcpBaseUrl = '', fetchCloudAuthApi, workspaceSwitchingEnabled = false, currentWorkspaceRole = 'member', currentWorkspaceName = '', onDeleteWorkspace, onMcpHostRootChange, onOpenCloudAuth, isAuthenticated = false, exportEnvironment, setupState = null, buildInfo = null, onExportEnvironmentChange, onSaveSetupMode, onSaveWorkspaceProfile, availableWorkflows = [], onExportWorkflows, initiativeTemplates = [], onRefreshInitiativeTemplates, onCreateInitiativeFromTemplate, onRefreshWorkflows } = settingsModel;
|
|
19
20
|
const showJsonBackupSettings = runtimeMode !== 'cloud';
|
|
20
21
|
// Workflow Selection State
|
|
21
22
|
const [selectedWorkflows, setSelectedWorkflows] = useState([]);
|
|
@@ -39,7 +40,7 @@ export function TaskSettings(props) {
|
|
|
39
40
|
const [selectedInitiativeTemplateId, setSelectedInitiativeTemplateId] = useState('');
|
|
40
41
|
const [initiativeTitle, setInitiativeTitle] = useState('');
|
|
41
42
|
const [isCreatingInitiative, setIsCreatingInitiative] = useState(false);
|
|
42
|
-
const [activeTab, setActiveTab] = useState('general');
|
|
43
|
+
const [activeTab, setActiveTab] = useState(() => isMcpOnly ? 'mcp' : 'general');
|
|
43
44
|
const [appearanceExpanded, setAppearanceExpanded] = useState(true);
|
|
44
45
|
const [generalScopeTab, setGeneralScopeTab] = useState(() => {
|
|
45
46
|
return 'project';
|
|
@@ -64,7 +65,6 @@ export function TaskSettings(props) {
|
|
|
64
65
|
? data.assignees.filter((a) => a.kind === 'agent').map((a) => ({
|
|
65
66
|
id: String(a.value || ''),
|
|
66
67
|
name: String(a.label || ''),
|
|
67
|
-
profileToken: typeof a.profileToken === 'string' ? a.profileToken : null,
|
|
68
68
|
username: String(a.username || a.value || ''),
|
|
69
69
|
icon: String(a.icon || 'Bot'),
|
|
70
70
|
color: String(a.color || '#6B7280'),
|
|
@@ -145,7 +145,6 @@ export function TaskSettings(props) {
|
|
|
145
145
|
const Icon = THEME_ICON_MAP[themeOption.icon];
|
|
146
146
|
return (_jsxs("button", { className: `${styles.themeBtn} tf-button-tile ${activeTheme === themeOption.id ? styles.activeTheme : ''}`, onClick: () => { void onSelect(themeOption.id); }, children: [_jsx(Icon, { size: 20 }), " ", themeOption.label] }, themeOption.id));
|
|
147
147
|
};
|
|
148
|
-
const cloudMcpAvailable = runtimeMode === 'cloud' || isAuthenticated;
|
|
149
148
|
const defaultMcpMode = runtimeMode === 'cloud'
|
|
150
149
|
? 'cloud'
|
|
151
150
|
: 'local';
|
|
@@ -153,7 +152,6 @@ export function TaskSettings(props) {
|
|
|
153
152
|
const [copiedConfig, setCopiedConfig] = useState(false);
|
|
154
153
|
const [useGlobalMcp, setUseGlobalMcp] = useState(true);
|
|
155
154
|
const [showAdvancedMcp, setShowAdvancedMcp] = useState(false);
|
|
156
|
-
const [showMcpConnectionTest, setShowMcpConnectionTest] = useState(false);
|
|
157
155
|
const [showMcpTokensList, setShowMcpTokensList] = useState(true);
|
|
158
156
|
const [mcpTokens, setMcpTokens] = useState([]);
|
|
159
157
|
const [mcpTokensLoading, setMcpTokensLoading] = useState(false);
|
|
@@ -169,10 +167,11 @@ export function TaskSettings(props) {
|
|
|
169
167
|
}, [currentWorkspaceName, setupState?.workspace?.name, projectName, workspaceId]);
|
|
170
168
|
const [newTokenName, setNewTokenName] = useState(defaultTokenName);
|
|
171
169
|
const [newTokenExpiresAt, setNewTokenExpiresAt] = useState('');
|
|
172
|
-
const [
|
|
170
|
+
const [mcpTokenIssueNotice, setMcpTokenIssueNotice] = useState(null);
|
|
171
|
+
const [mcpConfigNotice, setMcpConfigNotice] = useState(null);
|
|
172
|
+
const [mcpTokenListNotice, setMcpTokenListNotice] = useState(null);
|
|
173
173
|
const [generatedTokenValue, setGeneratedTokenValue] = useState(null);
|
|
174
174
|
const [selectedMcpClient, setSelectedMcpClient] = useState('general');
|
|
175
|
-
const [mcpConnectionToken, setMcpConnectionToken] = useState('');
|
|
176
175
|
const [mcpConnectionBusy, setMcpConnectionBusy] = useState(false);
|
|
177
176
|
const [mcpConnectionResult, setMcpConnectionResult] = useState(null);
|
|
178
177
|
const [mcpConnectorGrants, setMcpConnectorGrants] = useState([]);
|
|
@@ -186,17 +185,23 @@ export function TaskSettings(props) {
|
|
|
186
185
|
setNewTokenName((current) => current.trim().length > 0 ? current : defaultTokenName);
|
|
187
186
|
}, [defaultTokenName]);
|
|
188
187
|
useEffect(() => {
|
|
189
|
-
if (!
|
|
188
|
+
if (!mcpTokenIssueNotice)
|
|
190
189
|
return;
|
|
191
|
-
const timer = setTimeout(() =>
|
|
190
|
+
const timer = setTimeout(() => setMcpTokenIssueNotice(null), 3500);
|
|
192
191
|
return () => clearTimeout(timer);
|
|
193
|
-
}, [
|
|
192
|
+
}, [mcpTokenIssueNotice]);
|
|
194
193
|
useEffect(() => {
|
|
195
|
-
if (!
|
|
194
|
+
if (!mcpConfigNotice)
|
|
196
195
|
return;
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
}, [
|
|
196
|
+
const timer = setTimeout(() => setMcpConfigNotice(null), 3500);
|
|
197
|
+
return () => clearTimeout(timer);
|
|
198
|
+
}, [mcpConfigNotice]);
|
|
199
|
+
useEffect(() => {
|
|
200
|
+
if (!mcpTokenListNotice)
|
|
201
|
+
return;
|
|
202
|
+
const timer = setTimeout(() => setMcpTokenListNotice(null), 3500);
|
|
203
|
+
return () => clearTimeout(timer);
|
|
204
|
+
}, [mcpTokenListNotice]);
|
|
200
205
|
const cloudMcpEndpoint = useMemo(() => {
|
|
201
206
|
const inferredMcpBase = resolveTaskforceMcpBaseUrlFromBaseUrl(cloudMcpBaseUrl || cloudAuthBaseUrl || '');
|
|
202
207
|
const configuredBase = String(inferredMcpBase || cloudMcpBaseUrl || cloudAuthBaseUrl || '').trim().replace(/\/+$/, '');
|
|
@@ -207,9 +212,10 @@ export function TaskSettings(props) {
|
|
|
207
212
|
return `${window.location.origin.replace(/\/+$/, '')}/mcp`;
|
|
208
213
|
}, [cloudMcpBaseUrl, cloudAuthBaseUrl]);
|
|
209
214
|
const localMcpEnabled = runtimeMode !== 'cloud';
|
|
210
|
-
const showMcpModeToggle = localMcpEnabled
|
|
215
|
+
const showMcpModeToggle = localMcpEnabled;
|
|
211
216
|
const showCloudMcp = runtimeMode === 'cloud' || selectedMcpMode === 'cloud';
|
|
212
|
-
const showLocalMcp = runtimeMode !== 'cloud' &&
|
|
217
|
+
const showLocalMcp = runtimeMode !== 'cloud' && selectedMcpMode === 'local';
|
|
218
|
+
const canUseCloudMcp = isAuthenticated;
|
|
213
219
|
const sortedMcpTokens = useMemo(() => {
|
|
214
220
|
const statusRank = {
|
|
215
221
|
active: 0,
|
|
@@ -224,7 +230,8 @@ export function TaskSettings(props) {
|
|
|
224
230
|
});
|
|
225
231
|
}, [mcpTokens]);
|
|
226
232
|
const cloudMcpServerId = useMemo(() => buildCloudMcpServerId(currentWorkspaceName || null, projectName || null), [currentWorkspaceName, projectName]);
|
|
227
|
-
const
|
|
233
|
+
const currentMcpTokenValue = generatedTokenValue?.trim() || '';
|
|
234
|
+
const cloudMcpTokenValue = currentMcpTokenValue || '<<GENERATE_TOKEN>>';
|
|
228
235
|
// Launch decision: keep generated Cloud MCP config identity-neutral for shared connections.
|
|
229
236
|
const cloudClientIntegration = useMemo(() => buildCloudMcpClientIntegration({
|
|
230
237
|
clientId: selectedMcpClient,
|
|
@@ -241,6 +248,7 @@ export function TaskSettings(props) {
|
|
|
241
248
|
? cloudClientIntegration.serverConfig ?? null
|
|
242
249
|
: null;
|
|
243
250
|
const selectedMcpClientUsesOAuth = selectedMcpClient === 'chatgpt-desktop' || selectedMcpClient === 'claude-desktop';
|
|
251
|
+
const agentRegistrationPrompt = 'Resolve your profile with Taskforce.';
|
|
244
252
|
const activeChatGptConnector = useMemo(() => mcpConnectorGrants.find((grant) => grant.provider === 'chatgpt' && grant.status === 'active') || null, [mcpConnectorGrants]);
|
|
245
253
|
const activeClaudeConnector = useMemo(() => mcpConnectorGrants.find((grant) => grant.provider === 'claude' && grant.status === 'active') || null, [mcpConnectorGrants]);
|
|
246
254
|
const selectedConnectorGrant = selectedMcpClient === 'chatgpt-desktop'
|
|
@@ -287,14 +295,17 @@ export function TaskSettings(props) {
|
|
|
287
295
|
setCopiedConfig(mode);
|
|
288
296
|
setTimeout(() => setCopiedConfig(false), 2000);
|
|
289
297
|
};
|
|
298
|
+
const renderMcpProfilePrompt = () => (_jsxs("div", { className: styles.mcpRegistrationHint, children: [_jsx("span", { children: "Once the MCP is configured, prompt your agent:" }), _jsx("button", { type: "button", className: styles.mcpRegistrationPrompt, onClick: () => copyToClipboard(agentRegistrationPrompt, 'registration'), title: copiedConfig === 'registration' ? 'Copied' : 'Copy prompt', children: agentRegistrationPrompt })] }));
|
|
299
|
+
const renderCloudMcpAuthRequired = () => (_jsxs("div", { className: `${styles.mcpAuthRequiredCard} ${styles.marginTop16}`, children: [_jsx("div", { className: styles.mcpAuthRequiredIcon, children: _jsx(Plug, { size: 20 }) }), _jsxs("div", { className: styles.mcpAuthRequiredBody, children: [_jsx("h3", { className: styles.settingTitle, children: "Sign in to use Cloud MCP" }), _jsx("p", { className: styles.settingDescription, children: "Cloud MCP connects remote agents through your Taskforce cloud account. Register or sign in to generate cloud MCP tokens, copy client configuration, and connect hosted MCP agents to this workspace." }), onOpenCloudAuth && (_jsxs("div", { className: styles.mcpAuthRequiredActions, children: [_jsx("button", { type: "button", className: styles.copyBtn, onClick: () => onOpenCloudAuth('login'), children: "Sign In" }), _jsx("button", { type: "button", className: styles.copyBtn, onClick: () => onOpenCloudAuth('register'), children: "Register" })] }))] })] }));
|
|
290
300
|
const handleCopyCloudMcpConfig = () => {
|
|
291
|
-
if (!selectedMcpClientUsesOAuth && !
|
|
292
|
-
|
|
301
|
+
if (!selectedMcpClientUsesOAuth && !currentMcpTokenValue) {
|
|
302
|
+
setMcpConfigNotice({
|
|
293
303
|
type: 'error',
|
|
294
304
|
message: 'Generate a token before copying the Cloud MCP configuration.'
|
|
295
305
|
});
|
|
296
306
|
return;
|
|
297
307
|
}
|
|
308
|
+
setMcpConfigNotice(null);
|
|
298
309
|
copyToClipboard(cloudMcpFullConfig, 'full');
|
|
299
310
|
};
|
|
300
311
|
const buildMcpServerConfig = () => {
|
|
@@ -321,7 +332,8 @@ export function TaskSettings(props) {
|
|
|
321
332
|
: 'your-workspace-id';
|
|
322
333
|
const env = {
|
|
323
334
|
TASKFORCE_TENANT_ID: resolvedTenantId,
|
|
324
|
-
TASKFORCE_WORKSPACE_ID: resolvedWorkspaceId
|
|
335
|
+
TASKFORCE_WORKSPACE_ID: resolvedWorkspaceId,
|
|
336
|
+
...buildLocalAiProfileEnv(selectedMcpClient)
|
|
325
337
|
};
|
|
326
338
|
const serverConfig = useGlobalMcp
|
|
327
339
|
? {
|
|
@@ -350,6 +362,7 @@ export function TaskSettings(props) {
|
|
|
350
362
|
tenantId,
|
|
351
363
|
workspaceId,
|
|
352
364
|
setupState?.workspaceId,
|
|
365
|
+
selectedMcpClient,
|
|
353
366
|
useGlobalMcp
|
|
354
367
|
]);
|
|
355
368
|
const localClientIntegration = useMemo(() => buildLocalMcpClientIntegration({
|
|
@@ -383,7 +396,7 @@ export function TaskSettings(props) {
|
|
|
383
396
|
copyToClipboard(toCopy, mode);
|
|
384
397
|
};
|
|
385
398
|
const loadMcpTokens = async () => {
|
|
386
|
-
if (!
|
|
399
|
+
if (!canUseCloudMcp)
|
|
387
400
|
return;
|
|
388
401
|
setMcpTokensLoading(true);
|
|
389
402
|
setMcpTokensError(null);
|
|
@@ -407,7 +420,7 @@ export function TaskSettings(props) {
|
|
|
407
420
|
}
|
|
408
421
|
};
|
|
409
422
|
const loadMcpConnectors = async () => {
|
|
410
|
-
if (!
|
|
423
|
+
if (!canUseCloudMcp)
|
|
411
424
|
return;
|
|
412
425
|
setMcpConnectorsLoading(true);
|
|
413
426
|
setMcpConnectorsError(null);
|
|
@@ -433,11 +446,12 @@ export function TaskSettings(props) {
|
|
|
433
446
|
const handleCreateMcpToken = async () => {
|
|
434
447
|
const trimmedName = newTokenName.trim();
|
|
435
448
|
if (!trimmedName) {
|
|
436
|
-
|
|
449
|
+
setMcpTokenIssueNotice({ type: 'error', message: 'Token name is required.' });
|
|
437
450
|
return;
|
|
438
451
|
}
|
|
439
452
|
setMcpActionBusyId('create');
|
|
440
|
-
|
|
453
|
+
setMcpTokenIssueNotice(null);
|
|
454
|
+
setMcpConnectionResult(null);
|
|
441
455
|
try {
|
|
442
456
|
const res = await fetchCloudAuthApi('/api/taskforce/settings/mcp/tokens', {
|
|
443
457
|
method: 'POST',
|
|
@@ -451,10 +465,11 @@ export function TaskSettings(props) {
|
|
|
451
465
|
});
|
|
452
466
|
const payload = await res.json().catch(() => ({}));
|
|
453
467
|
if (!res.ok) {
|
|
454
|
-
|
|
468
|
+
setMcpTokenIssueNotice({ type: 'error', message: String(payload?.error || 'Failed to create token.') });
|
|
455
469
|
return;
|
|
456
470
|
}
|
|
457
471
|
setGeneratedTokenValue(String(payload?.token || ''));
|
|
472
|
+
setMcpConnectionResult(null);
|
|
458
473
|
setNewTokenName(defaultTokenName);
|
|
459
474
|
setNewTokenExpiresAt('');
|
|
460
475
|
setMcpTokens((current) => {
|
|
@@ -463,31 +478,45 @@ export function TaskSettings(props) {
|
|
|
463
478
|
});
|
|
464
479
|
}
|
|
465
480
|
catch {
|
|
466
|
-
|
|
481
|
+
setMcpTokenIssueNotice({ type: 'error', message: 'Failed to create token.' });
|
|
467
482
|
}
|
|
468
483
|
finally {
|
|
469
484
|
setMcpActionBusyId(null);
|
|
470
485
|
}
|
|
471
486
|
};
|
|
472
487
|
const handleMcpTokenAction = async (tokenId, action) => {
|
|
488
|
+
if (action === 'delete' && !window.confirm('Delete this token record? This does not affect active tokens.')) {
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
473
491
|
setMcpActionBusyId(`${action}:${tokenId}`);
|
|
474
|
-
|
|
492
|
+
setMcpTokenListNotice(null);
|
|
475
493
|
try {
|
|
476
|
-
const
|
|
477
|
-
|
|
494
|
+
const path = action === 'delete'
|
|
495
|
+
? `/api/taskforce/settings/mcp/tokens/${encodeURIComponent(tokenId)}`
|
|
496
|
+
: `/api/taskforce/settings/mcp/tokens/${encodeURIComponent(tokenId)}/${action}`;
|
|
497
|
+
const res = await fetchCloudAuthApi(path, {
|
|
498
|
+
method: action === 'delete' ? 'DELETE' : 'POST',
|
|
478
499
|
credentials: 'include'
|
|
479
500
|
});
|
|
480
501
|
const payload = await res.json().catch(() => ({}));
|
|
481
502
|
if (!res.ok) {
|
|
482
|
-
|
|
503
|
+
setMcpTokenListNotice({ type: 'error', message: String(payload?.error || `Failed to ${action} token.`) });
|
|
483
504
|
return;
|
|
484
505
|
}
|
|
485
506
|
if (action === 'regenerate') {
|
|
486
507
|
setGeneratedTokenValue(String(payload?.token || ''));
|
|
487
|
-
|
|
508
|
+
setMcpConnectionResult(null);
|
|
509
|
+
setMcpTokenListNotice({ type: 'success', message: 'Token regenerated. Copy the new value from the Full Token field.' });
|
|
510
|
+
}
|
|
511
|
+
else if (action === 'delete') {
|
|
512
|
+
setMcpTokenListNotice({ type: 'success', message: 'Token deleted.' });
|
|
488
513
|
}
|
|
489
514
|
else {
|
|
490
|
-
|
|
515
|
+
setMcpTokenListNotice({ type: 'success', message: 'Token revoked.' });
|
|
516
|
+
}
|
|
517
|
+
if (action === 'delete') {
|
|
518
|
+
setMcpTokens((current) => current.filter((item) => item.id !== tokenId));
|
|
519
|
+
return;
|
|
491
520
|
}
|
|
492
521
|
const nextRecord = payload?.record || null;
|
|
493
522
|
if (nextRecord?.id) {
|
|
@@ -498,18 +527,18 @@ export function TaskSettings(props) {
|
|
|
498
527
|
}
|
|
499
528
|
}
|
|
500
529
|
catch {
|
|
501
|
-
|
|
530
|
+
setMcpTokenListNotice({ type: 'error', message: `Failed to ${action} token.` });
|
|
502
531
|
}
|
|
503
532
|
finally {
|
|
504
533
|
setMcpActionBusyId(null);
|
|
505
534
|
}
|
|
506
535
|
};
|
|
507
536
|
const handleTestMcpConnection = async () => {
|
|
508
|
-
const trimmedToken =
|
|
537
|
+
const trimmedToken = currentMcpTokenValue;
|
|
509
538
|
if (!trimmedToken) {
|
|
510
539
|
setMcpConnectionResult({
|
|
511
540
|
type: 'error',
|
|
512
|
-
message: '
|
|
541
|
+
message: 'Generate or paste a full token before testing the MCP connection.'
|
|
513
542
|
});
|
|
514
543
|
return;
|
|
515
544
|
}
|
|
@@ -618,7 +647,7 @@ export function TaskSettings(props) {
|
|
|
618
647
|
}
|
|
619
648
|
};
|
|
620
649
|
useEffect(() => {
|
|
621
|
-
if (!
|
|
650
|
+
if (!canUseCloudMcp)
|
|
622
651
|
return;
|
|
623
652
|
if (activeTab === 'mcp' && showCloudMcp) {
|
|
624
653
|
void loadMcpTokens();
|
|
@@ -628,7 +657,7 @@ export function TaskSettings(props) {
|
|
|
628
657
|
if (activeTab === 'integrations') {
|
|
629
658
|
void loadMcpConnectors();
|
|
630
659
|
}
|
|
631
|
-
}, [activeTab, showCloudMcp,
|
|
660
|
+
}, [activeTab, showCloudMcp, canUseCloudMcp]);
|
|
632
661
|
useEffect(() => {
|
|
633
662
|
if (activeTab === 'initiatives' && initiativeTemplates.length === 0) {
|
|
634
663
|
onRefreshInitiativeTemplates?.();
|
|
@@ -677,6 +706,9 @@ export function TaskSettings(props) {
|
|
|
677
706
|
else if (initialSection === 'agents') {
|
|
678
707
|
setActiveTab('agents');
|
|
679
708
|
}
|
|
709
|
+
else if (initialSection === 'mcp') {
|
|
710
|
+
setActiveTab(isMcpOnly ? 'mcp' : 'general');
|
|
711
|
+
}
|
|
680
712
|
else if (initialSection === 'integrations') {
|
|
681
713
|
setActiveTab('integrations');
|
|
682
714
|
}
|
|
@@ -684,7 +716,7 @@ export function TaskSettings(props) {
|
|
|
684
716
|
setActiveTab(initialSection);
|
|
685
717
|
}
|
|
686
718
|
}
|
|
687
|
-
}, [initialSection]);
|
|
719
|
+
}, [initialSection, isMcpOnly]);
|
|
688
720
|
useEffect(() => {
|
|
689
721
|
if (activeTab === 'appearanceApplication' || activeTab === 'appearanceTaskCards' || activeTab === 'appearanceTaskForms') {
|
|
690
722
|
setAppearanceExpanded(true);
|
|
@@ -708,8 +740,7 @@ export function TaskSettings(props) {
|
|
|
708
740
|
const settingsNavItems = [
|
|
709
741
|
{ key: 'general', label: 'General', icon: _jsx(Settings, { size: 14 }), section: 'general' },
|
|
710
742
|
{ key: 'taxonomy', label: 'Taxonomy', icon: _jsx(Layers, { size: 14 }), section: 'taxonomy' },
|
|
711
|
-
{ key: 'integrations', label: 'Integrations', icon: _jsx(Plug, { size: 14 }), section: 'integrations' }
|
|
712
|
-
{ key: 'mcp', label: 'MCP', icon: _jsx(Box, { size: 14 }), section: 'mcp' }
|
|
743
|
+
{ key: 'integrations', label: 'Integrations', icon: _jsx(Plug, { size: 14 }), section: 'integrations' }
|
|
713
744
|
];
|
|
714
745
|
const appearanceNavItems = [
|
|
715
746
|
{ key: 'appearanceApplication', label: 'Application', section: 'appearance-application' },
|
|
@@ -737,7 +768,7 @@ export function TaskSettings(props) {
|
|
|
737
768
|
message: success ? 'Checklist dropdown setting saved.' : 'Failed to save checklist dropdown setting.'
|
|
738
769
|
});
|
|
739
770
|
}, disabled: !onChecklistDropdownEnabledChange }), _jsx("span", { children: "Enable checklist dropdown in task form" })] })] }));
|
|
740
|
-
return (_jsx("div", { className: styles.settingsTab, children: _jsxs("div", { className: styles.settingsLayout, children: [_jsxs("aside", { className: styles.settingsSidebar, children: [_jsx("div", { className: styles.settingsSidebarHeader, children: "Sections" }), _jsxs("div", { className: `${styles.settingsSidebarNav} tf-scrollbar tf-scrollbar--track-transparent tf-scrollbar--compact`, children: [settingsNavItems.filter((item) => item.key === 'general').map((item) => (_jsxs("button", { className: `${styles.settingsSidebarBtn} ${activeTab === item.key ? styles.settingsSidebarBtnActive : ''}`, onClick: () => selectTab(item.key, item.section), children: [item.icon, _jsx("span", { children: item.label })] }, item.key))), _jsxs("div", { className: styles.settingsSidebarGroup, children: [_jsxs("button", { className: `${styles.settingsSidebarBtn} ${styles.settingsSidebarGroupBtn} ${(activeTab === 'appearanceApplication' || activeTab === 'appearanceTaskCards' || activeTab === 'appearanceTaskForms') ? styles.settingsSidebarBtnActive : ''}`, onClick: () => setAppearanceExpanded((current) => !current), "aria-expanded": appearanceExpanded, "aria-controls": "settings-appearance-nav", children: [_jsx(Sparkles, { size: 14 }), _jsx("span", { className: styles.settingsSidebarGroupLabel, children: "Appearance" }), _jsx("span", { className: styles.settingsSidebarGroupChevron, children: appearanceExpanded ? _jsx(ChevronDown, { size: 14 }) : _jsx(ChevronRight, { size: 14 }) })] }), appearanceExpanded && (_jsx("div", { id: "settings-appearance-nav", className: styles.settingsSidebarSubnav, children: appearanceNavItems.map((item) => (_jsx("button", { className: `${styles.settingsSidebarSubBtn} ${activeTab === item.key ? styles.settingsSidebarBtnActive : ''}`, onClick: () => selectTab(item.key, item.section), children: _jsx("span", { children: item.label }) }, item.key))) }))] }), settingsNavItems.filter((item) => item.key !== 'general').map((item) => (_jsxs("button", { className: `${styles.settingsSidebarBtn} ${activeTab === item.key ? styles.settingsSidebarBtnActive : ''}`, onClick: () => selectTab(item.key, item.section), children: [item.icon, _jsx("span", { children: item.label })] }, item.key)))] })] }), _jsxs("div", { className: styles.settingsContent, children: [settingsFeedback && (_jsxs("div", { className: `${styles.settingsToast} ${settingsFeedback.type === 'success' ? styles.settingsToastSuccess : styles.settingsToastError}`, children: [settingsFeedback.type === 'success' ? _jsx(Check, { size: 14 }) : _jsx(AlertTriangle, { size: 14 }), _jsx("span", { children: settingsFeedback.message })] })), activeTab === 'general' && (_jsxs(_Fragment, { children: [_jsxs("div", { className: styles.settingGroup, children: [_jsxs("div", { className: `${styles.settingsTabs} tf-scrollbar tf-scrollbar--track-transparent tf-scrollbar--compact`, children: [_jsx("button", { className: `${styles.settingsTabBtn} ${generalScopeTab === 'project' ? styles.settingsTabBtnActive : ''}`, onClick: () => setGeneralScopeTab('project'), children: "Project" }), _jsx("button", { className: `${styles.settingsTabBtn} ${generalScopeTab === 'global' ? styles.settingsTabBtnActive : ''}`, onClick: () => setGeneralScopeTab('global'), children: "Global" })] }), generalScopeTab === 'project' && (_jsx("div", { className: styles.pathInputGroup, style: { justifyContent: 'flex-end' }, children: _jsx("button", { onClick: async () => {
|
|
771
|
+
return (_jsx("div", { className: `${styles.settingsTab} ${isMcpOnly ? styles.settingsTabMcpOnly : ''}`.trim(), children: _jsxs("div", { className: `${styles.settingsLayout} ${isMcpOnly ? styles.settingsLayoutMcpOnly : ''}`.trim(), children: [!isMcpOnly && (_jsxs("aside", { className: styles.settingsSidebar, children: [_jsx("div", { className: styles.settingsSidebarHeader, children: "Sections" }), _jsxs("div", { className: `${styles.settingsSidebarNav} tf-scrollbar tf-scrollbar--track-transparent tf-scrollbar--compact`, children: [settingsNavItems.filter((item) => item.key === 'general').map((item) => (_jsxs("button", { className: `${styles.settingsSidebarBtn} ${activeTab === item.key ? styles.settingsSidebarBtnActive : ''}`, onClick: () => selectTab(item.key, item.section), children: [item.icon, _jsx("span", { children: item.label })] }, item.key))), _jsxs("div", { className: styles.settingsSidebarGroup, children: [_jsxs("button", { className: `${styles.settingsSidebarBtn} ${styles.settingsSidebarGroupBtn} ${(activeTab === 'appearanceApplication' || activeTab === 'appearanceTaskCards' || activeTab === 'appearanceTaskForms') ? styles.settingsSidebarBtnActive : ''}`, onClick: () => setAppearanceExpanded((current) => !current), "aria-expanded": appearanceExpanded, "aria-controls": "settings-appearance-nav", children: [_jsx(Sparkles, { size: 14 }), _jsx("span", { className: styles.settingsSidebarGroupLabel, children: "Appearance" }), _jsx("span", { className: styles.settingsSidebarGroupChevron, children: appearanceExpanded ? _jsx(ChevronDown, { size: 14 }) : _jsx(ChevronRight, { size: 14 }) })] }), appearanceExpanded && (_jsx("div", { id: "settings-appearance-nav", className: styles.settingsSidebarSubnav, children: appearanceNavItems.map((item) => (_jsx("button", { className: `${styles.settingsSidebarSubBtn} ${activeTab === item.key ? styles.settingsSidebarBtnActive : ''}`, onClick: () => selectTab(item.key, item.section), children: _jsx("span", { children: item.label }) }, item.key))) }))] }), settingsNavItems.filter((item) => item.key !== 'general').map((item) => (_jsxs("button", { className: `${styles.settingsSidebarBtn} ${activeTab === item.key ? styles.settingsSidebarBtnActive : ''}`, onClick: () => selectTab(item.key, item.section), children: [item.icon, _jsx("span", { children: item.label })] }, item.key)))] })] })), _jsxs("div", { className: styles.settingsContent, children: [settingsFeedback && (_jsxs("div", { className: `${styles.settingsToast} ${settingsFeedback.type === 'success' ? styles.settingsToastSuccess : styles.settingsToastError}`, children: [settingsFeedback.type === 'success' ? _jsx(Check, { size: 14 }) : _jsx(AlertTriangle, { size: 14 }), _jsx("span", { children: settingsFeedback.message })] })), activeTab === 'general' && (_jsxs(_Fragment, { children: [_jsxs("div", { className: styles.settingGroup, children: [_jsxs("div", { className: `${styles.settingsTabs} tf-scrollbar tf-scrollbar--track-transparent tf-scrollbar--compact`, children: [_jsx("button", { className: `${styles.settingsTabBtn} ${generalScopeTab === 'project' ? styles.settingsTabBtnActive : ''}`, onClick: () => setGeneralScopeTab('project'), children: "Project" }), _jsx("button", { className: `${styles.settingsTabBtn} ${generalScopeTab === 'global' ? styles.settingsTabBtnActive : ''}`, onClick: () => setGeneralScopeTab('global'), children: "Global" })] }), generalScopeTab === 'project' && (_jsx("div", { className: styles.pathInputGroup, style: { justifyContent: 'flex-end' }, children: _jsx("button", { onClick: async () => {
|
|
741
772
|
const confirmed = window.confirm('Reset project Theme and Backups to global defaults?');
|
|
742
773
|
if (!confirmed)
|
|
743
774
|
return;
|
|
@@ -882,56 +913,30 @@ export function TaskSettings(props) {
|
|
|
882
913
|
});
|
|
883
914
|
}, initialTab: (initialSection === 'categories' || initialSection === 'types' || initialSection === 'priorities')
|
|
884
915
|
? initialSection
|
|
885
|
-
: undefined })] })), activeTab === 'mcp' && (_jsxs("div", { className: styles.settingsGroup, children: [showMcpModeToggle && (_jsxs("div", { className: styles.settingsTabs, children: [_jsx("button", { className: `${styles.settingsTabBtn} ${selectedMcpMode === 'local' ? styles.settingsTabBtnActive : ''}`, onClick: () => setSelectedMcpMode('local'), children: "Local MCP" }), _jsx("button", { className: `${styles.settingsTabBtn} ${selectedMcpMode === 'cloud' ? styles.settingsTabBtnActive : ''}`, onClick: () => setSelectedMcpMode('cloud'), children: "Cloud MCP" })] })), showCloudMcp && (_jsx(_Fragment, { children: selectedMcpClientUsesOAuth ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: styles.settingGroup, children: [_jsxs("div", { className: styles.settingLabelGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "OAuth Connector Setup" }), _jsx("span", { className: styles.settingDescription, children: selectedMcpClient === 'chatgpt-desktop'
|
|
916
|
+
: undefined })] })), activeTab === 'mcp' && (_jsxs("div", { className: styles.settingsGroup, children: [showMcpModeToggle && (_jsxs("div", { className: styles.settingsTabs, children: [_jsx("button", { className: `${styles.settingsTabBtn} ${selectedMcpMode === 'local' ? styles.settingsTabBtnActive : ''}`, onClick: () => setSelectedMcpMode('local'), children: "Local MCP" }), _jsx("button", { className: `${styles.settingsTabBtn} ${selectedMcpMode === 'cloud' ? styles.settingsTabBtnActive : ''}`, onClick: () => setSelectedMcpMode('cloud'), children: "Cloud MCP" })] })), showCloudMcp && !canUseCloudMcp && (_jsxs(_Fragment, { children: [_jsx("div", { className: `${styles.settingGroup} ${styles.marginTop16}`, children: _jsxs("div", { className: styles.settingLabelGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "Cloud MCP" }), _jsx("span", { className: styles.settingDescription, children: "Cloud MCP connects agents to Taskforce through the hosted MCP endpoint. Use this for remote MCP clients or tools that cannot access your local Taskforce install." })] }) }), renderCloudMcpAuthRequired()] })), showCloudMcp && canUseCloudMcp && (_jsx(_Fragment, { children: selectedMcpClientUsesOAuth ? (_jsxs(_Fragment, { children: [_jsx("div", { className: `${styles.settingGroup} ${styles.marginTop16}`, children: _jsxs("div", { className: styles.settingLabelGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "Cloud MCP" }), _jsx("span", { className: styles.settingDescription, children: "Cloud MCP connects agents to Taskforce through the hosted MCP endpoint. Use this for remote MCP clients or tools that cannot access your local Taskforce install." })] }) }), _jsxs("div", { className: styles.settingGroup, children: [_jsxs("div", { className: styles.settingLabelGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "OAuth Connector Setup" }), _jsx("span", { className: styles.settingDescription, children: selectedMcpClient === 'chatgpt-desktop'
|
|
886
917
|
? 'ChatGPT Desktop uses the Taskforce OAuth connector flow instead of a personal MCP token.'
|
|
887
918
|
: 'Claude Desktop uses the Taskforce OAuth connector flow instead of a personal MCP token.' })] }), _jsx("div", { className: `${selectedConnectorGrant ? styles.successMessage : styles.settingHelper} ${styles.marginTop12}`, children: selectedConnectorGrant ? (_jsxs(_Fragment, { children: [_jsx(Check, { size: 14 }), _jsxs("div", { children: [_jsx("div", { children: "Connector already authorized for this workspace." }), _jsxs("div", { className: styles.settingHelper, children: ["Last used ", selectedConnectorGrant.lastUsedAt
|
|
888
919
|
? new Date(selectedConnectorGrant.lastUsedAt).toLocaleString()
|
|
889
920
|
: 'not yet'] })] })] })) : ('No active connector authorization for this workspace yet.') }), _jsx("div", { className: styles.settingDescription, style: { marginTop: '12px' }, children: "Use the server URL above in your client, then finish the OAuth authorization flow from the Integrations tab." }), _jsx("div", { style: { display: 'flex', justifyContent: 'flex-end', width: '100%', marginTop: '12px' }, children: _jsx("button", { className: styles.copyBtn, onClick: () => setActiveTab('integrations'), children: "Open Integrations" }) })] }), _jsxs("div", { className: styles.settingGroup, children: [_jsxs("div", { className: `${styles.codeBlockWrapper} ${styles.codeBlockWrapperCustom} ${styles.marginTop12}`, style: { minHeight: '260px' }, children: [_jsxs("div", { className: styles.codeHeader, children: [_jsx("span", { className: styles.codeLabel, children: "Cloud MCP Configuration" }), _jsxs("div", { className: styles.codeHeaderActions, children: [_jsx("select", { className: styles.settingInput, value: selectedMcpClient, onChange: (e) => setSelectedMcpClient(e.target.value), "aria-label": "MCP client", style: { width: 'auto', minWidth: '170px', padding: '6px 12px', fontSize: '12px', borderRadius: '8px' }, children: MCP_CLIENT_OPTIONS.map((option) => (_jsx("option", { value: option.id, disabled: option.disabled, children: option.label }, option.id))) }), _jsx("button", { className: `${styles.copyBtn} ${copiedConfig === 'full' ? styles.copyBtnActive : ''}`, onClick: handleCopyCloudMcpConfig, title: "Copy full configuration file", children: copiedConfig === 'full' ? _jsx(Check, { size: 14 }) : _jsx(Copy, { size: 14 }) })] })] }), _jsx("pre", { className: styles.codeBlock, children: _jsx("code", { children: cloudMcpServerConfig
|
|
890
921
|
? renderMcpConfigBlock(cloudMcpServerId, cloudMcpServerConfig, cloudClientIntegration.rootKey || 'mcpServers', cloudClientIntegration.wrapperKeys || [])
|
|
891
|
-
: renderTextConfigBlock(cloudClientIntegration.renderedText || '') }) })] }), _jsxs("div", { className: `${styles.codeBlockWrapper} ${styles.marginTop12}`, children: [_jsx("div", { className: styles.codeHeader, children: _jsx("span", { className: styles.codeLabel, children: cloudClientIntegration.instructionLabel }) }),
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
const displayedGeneratedToken = tokenBarError
|
|
896
|
-
|| (copiedConfig === 'token'
|
|
897
|
-
? 'Copied to clipboard'
|
|
898
|
-
: (generatedTokenValue || ''));
|
|
899
|
-
return (_jsxs("div", { className: styles.mcpTokenOutputWrap, style: { cursor: generatedTokenValue ? 'pointer' : 'default' }, onClick: () => generatedTokenValue && copyToClipboard(generatedTokenValue, 'token'), role: generatedTokenValue ? 'button' : undefined, tabIndex: generatedTokenValue ? 0 : -1, onKeyDown: (e) => {
|
|
900
|
-
if (!generatedTokenValue)
|
|
901
|
-
return;
|
|
902
|
-
if (e.key === 'Enter' || e.key === ' ') {
|
|
903
|
-
e.preventDefault();
|
|
904
|
-
copyToClipboard(generatedTokenValue, 'token');
|
|
905
|
-
}
|
|
906
|
-
}, title: generatedTokenValue ? (copiedConfig === 'token' ? 'Token copied' : 'Click to copy token') : undefined, children: [_jsx("div", { className: styles.settingLabelGroup, children: _jsx("span", { className: styles.settingDescription, children: "Token" }) }), _jsx("div", { className: styles.mcpTokenValueField, style: {
|
|
907
|
-
color: tokenBarError ? 'var(--status-danger-strong, #f87171)' : undefined,
|
|
908
|
-
}, children: _jsx("span", { className: styles.mcpTokenValueText, children: _jsx("code", { children: displayedGeneratedToken }) }) })] }));
|
|
909
|
-
})(), _jsx("div", { className: styles.mcpTokenActionRow, children: _jsxs("button", { className: styles.copyBtn, onClick: () => void handleCreateMcpToken(), disabled: mcpActionBusyId === 'create', title: "Generate Token", "aria-label": "Generate Token", children: [mcpActionBusyId === 'create' ? _jsx(Loader2, { size: 14, className: styles.spinIcon }) : _jsx(Zap, { size: 14 }), _jsx("span", { children: "GENERATE TOKEN" })] }) })] }), _jsxs("div", { className: styles.settingGroup, children: [_jsxs("div", { className: `${styles.codeBlockWrapper} ${styles.codeBlockWrapperCustom} ${styles.marginTop12}`, style: { minHeight: '260px' }, children: [_jsxs("div", { className: styles.codeHeader, children: [_jsx("span", { className: styles.codeLabel, children: "Cloud MCP Configuration" }), _jsxs("div", { className: styles.codeHeaderActions, children: [_jsx("select", { className: styles.settingInput, value: selectedMcpClient, onChange: (e) => setSelectedMcpClient(e.target.value), "aria-label": "MCP client", style: { width: 'auto', minWidth: '170px', padding: '6px 12px', fontSize: '12px', borderRadius: '8px' }, children: MCP_CLIENT_OPTIONS.map((option) => (_jsx("option", { value: option.id, disabled: option.disabled, children: option.label }, option.id))) }), _jsx("button", { className: `${styles.copyBtn} ${copiedConfig === 'full' ? styles.copyBtnActive : ''}`, onClick: handleCopyCloudMcpConfig, title: "Copy full configuration file", children: copiedConfig === 'full' ? _jsx(Check, { size: 14 }) : _jsx(Copy, { size: 14 }) })] })] }), _jsx("pre", { className: styles.codeBlock, children: _jsx("code", { children: cloudMcpServerConfig
|
|
922
|
+
: renderTextConfigBlock(cloudClientIntegration.renderedText || '') }) })] }), mcpConfigNotice && (_jsxs("div", { className: `${mcpConfigNotice.type === 'success' ? styles.successMessage : styles.errorMessage} ${styles.marginTop12}`, children: [mcpConfigNotice.type === 'success' ? _jsx(Check, { size: 14 }) : _jsx(AlertTriangle, { size: 14 }), mcpConfigNotice.message] })), _jsxs("div", { className: `${styles.codeBlockWrapper} ${styles.marginTop12}`, children: [_jsx("div", { className: styles.codeHeader, children: _jsx("span", { className: styles.codeLabel, children: cloudClientIntegration.instructionLabel }) }), _jsxs("div", { style: { padding: '16px 20px' }, children: [_jsx("div", { className: styles.settingDescription, children: cloudClientIntegration.instructionText }), renderMcpProfilePrompt()] })] })] })] })) : (_jsxs(_Fragment, { children: [_jsx("div", { className: `${styles.settingGroup} ${styles.marginTop16}`, children: _jsxs("div", { className: styles.settingLabelGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "Cloud MCP" }), _jsx("span", { className: styles.settingDescription, children: "Cloud MCP connects agents to Taskforce through the hosted MCP endpoint. Use this for remote MCP clients or tools that cannot access your local Taskforce install." })] }) }), _jsxs("div", { className: `${styles.codeBlockWrapper} ${styles.codeBlockWrapperCustom} ${styles.marginTop16}`, children: [_jsx("div", { className: styles.codeHeader, children: _jsx("div", { className: styles.settingLabelGroup, style: { gap: '2px' }, children: _jsx("span", { className: styles.codeLabel, children: "Generate Token" }) }) }), _jsx("div", { className: styles.mcpTokenCardBody, children: _jsxs("div", { className: styles.mcpTokenFormGrid, children: [_jsxs("div", { className: styles.settingsItem, style: { gap: '6px' }, children: [_jsx("div", { className: styles.settingLabelGroup, children: _jsx("span", { className: styles.settingDescription, children: "Token Name" }) }), _jsx("input", { type: "text", className: styles.settingInput, placeholder: "Cursor on MacBook", value: newTokenName, onChange: (e) => setNewTokenName(e.target.value) })] }), _jsxs("div", { className: styles.settingsItem, style: { gap: '6px' }, children: [_jsx("div", { className: styles.settingLabelGroup, children: _jsx("span", { className: styles.settingDescription, children: "Expiry (Optional)" }) }), _jsx("input", { type: "date", className: `${styles.settingInput} ${styles.taskFormDateInput}`, value: newTokenExpiresAt, onChange: (e) => setNewTokenExpiresAt(e.target.value) })] })] }) }), _jsxs("div", { className: styles.mcpTokenOutputWrap, children: [_jsx("div", { className: styles.settingLabelGroup, children: _jsx("span", { className: styles.settingDescription, children: "Full Token" }) }), _jsx("input", { type: "text", className: `${styles.settingInput} ${styles.mcpTokenValueInput}`, placeholder: "Generate a token to populate the full secret", value: generatedTokenValue || '', onChange: (e) => {
|
|
923
|
+
setGeneratedTokenValue(e.target.value);
|
|
924
|
+
setMcpConnectionResult(null);
|
|
925
|
+
} })] }), _jsxs("div", { className: styles.mcpTokenActionRow, children: [_jsxs("button", { className: styles.copyBtn, onClick: () => void handleTestMcpConnection(), disabled: !currentMcpTokenValue || mcpConnectionBusy, title: "Test Token", "aria-label": "Test Token", children: [mcpConnectionBusy ? _jsx(Loader2, { size: 14, className: styles.spinIcon }) : _jsx(Zap, { size: 14 }), _jsx("span", { children: "TEST TOKEN" })] }), _jsxs("button", { className: `${styles.copyBtn} ${copiedConfig === 'token' ? styles.copyBtnActive : ''}`, onClick: () => currentMcpTokenValue && copyToClipboard(currentMcpTokenValue, 'token'), disabled: !currentMcpTokenValue, title: "Copy Token", "aria-label": "Copy Token", children: [copiedConfig === 'token' ? _jsx(Check, { size: 14 }) : _jsx(Copy, { size: 14 }), _jsx("span", { children: "COPY TOKEN" })] }), _jsxs("button", { className: styles.copyBtn, onClick: () => void handleCreateMcpToken(), disabled: mcpActionBusyId === 'create', title: "Generate Token", "aria-label": "Generate Token", children: [mcpActionBusyId === 'create' ? _jsx(Loader2, { size: 14, className: styles.spinIcon }) : _jsx(Zap, { size: 14 }), _jsx("span", { children: "GENERATE TOKEN" })] })] }), mcpTokenIssueNotice && (_jsxs("div", { className: `${mcpTokenIssueNotice.type === 'success' ? styles.successMessage : styles.errorMessage} ${styles.marginTop12}`, children: [mcpTokenIssueNotice.type === 'success' ? _jsx(Check, { size: 14 }) : _jsx(AlertTriangle, { size: 14 }), mcpTokenIssueNotice.message] })), mcpConnectionResult && (_jsxs("div", { className: `${mcpConnectionResult.type === 'success' ? styles.successMessage : styles.errorMessage} ${styles.marginTop12}`, children: [mcpConnectionResult.type === 'success' ? _jsx(Check, { size: 14 }) : _jsx(AlertTriangle, { size: 14 }), _jsxs("div", { children: [_jsx("div", { children: mcpConnectionResult.message }), mcpConnectionResult.type === 'success' && (mcpConnectionResult.workspaceName || mcpConnectionResult.workspaceId) && (_jsxs("div", { className: styles.settingHelper, children: ["Workspace: ", mcpConnectionResult.workspaceName || mcpConnectionResult.workspaceId, mcpConnectionResult.workspaceId ? ` (${mcpConnectionResult.workspaceId})` : ''] })), mcpConnectionResult.type === 'success' && Array.isArray(mcpConnectionResult.scopes) && mcpConnectionResult.scopes.length > 0 && (_jsxs("div", { className: styles.settingHelper, children: ["Granted scopes: ", mcpConnectionResult.scopes.join(', ')] })), mcpConnectionResult.endpoint && (_jsxs("div", { className: styles.settingHelper, children: ["Endpoint: ", mcpConnectionResult.endpoint] })), mcpConnectionResult.type === 'error' && mcpConnectionResult.errorCode && (_jsxs("div", { className: styles.settingHelper, children: ["Error code: ", mcpConnectionResult.errorCode] })), mcpConnectionResult.type === 'error' && mcpConnectionResult.followup && (_jsx("div", { className: styles.settingHelper, children: mcpConnectionResult.followup }))] })] }))] }), _jsxs("div", { className: styles.settingGroup, children: [_jsxs("div", { className: `${styles.codeBlockWrapper} ${styles.codeBlockWrapperCustom} ${styles.marginTop12}`, style: { minHeight: '260px' }, children: [_jsxs("div", { className: styles.codeHeader, children: [_jsx("span", { className: styles.codeLabel, children: "Cloud MCP Configuration" }), _jsxs("div", { className: styles.codeHeaderActions, children: [_jsx("select", { className: styles.settingInput, value: selectedMcpClient, onChange: (e) => setSelectedMcpClient(e.target.value), "aria-label": "MCP client", style: { width: 'auto', minWidth: '170px', padding: '6px 12px', fontSize: '12px', borderRadius: '8px' }, children: MCP_CLIENT_OPTIONS.map((option) => (_jsx("option", { value: option.id, disabled: option.disabled, children: option.label }, option.id))) }), _jsx("button", { className: `${styles.copyBtn} ${copiedConfig === 'full' ? styles.copyBtnActive : ''}`, onClick: handleCopyCloudMcpConfig, title: "Copy full configuration file", children: copiedConfig === 'full' ? _jsx(Check, { size: 14 }) : _jsx(Copy, { size: 14 }) })] })] }), _jsx("pre", { className: styles.codeBlock, children: _jsx("code", { children: cloudMcpServerConfig
|
|
910
926
|
? renderMcpConfigBlock(cloudMcpServerId, cloudMcpServerConfig, cloudClientIntegration.rootKey || 'mcpServers', cloudClientIntegration.wrapperKeys || [])
|
|
911
|
-
: renderTextConfigBlock(cloudClientIntegration.renderedText || '') }) })] }), _jsxs("div", { className: `${styles.codeBlockWrapper} ${styles.marginTop12}`, children: [_jsx("div", { className: styles.codeHeader, children: _jsx("span", { className: styles.codeLabel, children: cloudClientIntegration.instructionLabel }) }),
|
|
912
|
-
if (e.key === 'Enter' || e.key === ' ') {
|
|
913
|
-
e.preventDefault();
|
|
914
|
-
setShowMcpConnectionTest((prev) => !prev);
|
|
915
|
-
}
|
|
916
|
-
}, role: "button", tabIndex: 0, title: showMcpConnectionTest ? 'Hide connection test' : 'Show connection test', children: [_jsx("label", { className: styles.label, children: "Test Connection" }), showMcpConnectionTest ? _jsx(ChevronDown, { size: 14 }) : _jsx(ChevronRight, { size: 14 })] }), showMcpConnectionTest && (_jsxs(_Fragment, { children: [_jsx("div", { className: `${styles.settingDescription} ${styles.marginTop12}`, children: "Validate that a token works for this workspace before you paste it into your MCP client." }), _jsxs("div", { className: `${styles.settingsItem} ${styles.marginTop12}`, children: [_jsx("div", { className: styles.settingLabelGroup, children: _jsx("span", { className: styles.settingDescription, children: "Token to Test" }) }), _jsx("input", { type: "text", className: styles.settingInput, placeholder: "tfmcp_xxxxx_replace-me", value: mcpConnectionToken, onChange: (e) => {
|
|
917
|
-
setMcpConnectionToken(e.target.value);
|
|
918
|
-
setMcpConnectionResult(null);
|
|
919
|
-
} })] }), _jsxs("div", { className: styles.marginTop12, style: { display: 'flex', gap: '8px', flexWrap: 'wrap', justifyContent: 'flex-end' }, children: [generatedTokenValue && (_jsx("button", { className: styles.copyBtn, onClick: () => {
|
|
920
|
-
setMcpConnectionToken(generatedTokenValue);
|
|
921
|
-
setMcpConnectionResult(null);
|
|
922
|
-
}, children: "Use Generated Token" })), _jsxs("button", { className: styles.copyBtn, onClick: () => void handleTestMcpConnection(), disabled: mcpConnectionBusy, children: [mcpConnectionBusy ? _jsx(Loader2, { size: 14, className: styles.spinIcon }) : _jsx(Zap, { size: 14 }), "Test Connection"] })] }), mcpConnectionResult && (_jsxs("div", { className: `${mcpConnectionResult.type === 'success' ? styles.successMessage : styles.errorMessage} ${styles.marginTop12}`, children: [mcpConnectionResult.type === 'success' ? _jsx(Check, { size: 14 }) : _jsx(AlertTriangle, { size: 14 }), _jsxs("div", { children: [_jsx("div", { children: mcpConnectionResult.message }), mcpConnectionResult.type === 'success' && (mcpConnectionResult.workspaceName || mcpConnectionResult.workspaceId) && (_jsxs("div", { className: styles.settingHelper, children: ["Workspace: ", mcpConnectionResult.workspaceName || mcpConnectionResult.workspaceId, mcpConnectionResult.workspaceId ? ` (${mcpConnectionResult.workspaceId})` : ''] })), mcpConnectionResult.type === 'success' && Array.isArray(mcpConnectionResult.scopes) && mcpConnectionResult.scopes.length > 0 && (_jsxs("div", { className: styles.settingHelper, children: ["Granted scopes: ", mcpConnectionResult.scopes.join(', ')] })), mcpConnectionResult.endpoint && (_jsxs("div", { className: styles.settingHelper, children: ["Endpoint: ", mcpConnectionResult.endpoint] })), mcpConnectionResult.type === 'error' && mcpConnectionResult.errorCode && (_jsxs("div", { className: styles.settingHelper, children: ["Error code: ", mcpConnectionResult.errorCode] })), mcpConnectionResult.type === 'error' && mcpConnectionResult.followup && (_jsx("div", { className: styles.settingHelper, children: mcpConnectionResult.followup }))] })] }))] }))] }), _jsxs("div", { className: `${styles.settingGroup} ${styles.marginTop16}`, children: [_jsxs("div", { className: styles.toggleHeading, onClick: () => setShowMcpTokensList((prev) => !prev), onKeyDown: (e) => {
|
|
927
|
+
: renderTextConfigBlock(cloudClientIntegration.renderedText || '') }) })] }), mcpConfigNotice && (_jsxs("div", { className: `${mcpConfigNotice.type === 'success' ? styles.successMessage : styles.errorMessage} ${styles.marginTop12}`, children: [mcpConfigNotice.type === 'success' ? _jsx(Check, { size: 14 }) : _jsx(AlertTriangle, { size: 14 }), mcpConfigNotice.message] })), _jsxs("div", { className: `${styles.codeBlockWrapper} ${styles.marginTop12}`, children: [_jsx("div", { className: styles.codeHeader, children: _jsx("span", { className: styles.codeLabel, children: cloudClientIntegration.instructionLabel }) }), _jsxs("div", { style: { padding: '16px 20px' }, children: [_jsx("div", { className: styles.settingDescription, children: cloudClientIntegration.instructionText }), renderMcpProfilePrompt()] })] })] }), _jsxs("div", { className: `${styles.settingGroup} ${styles.marginTop16}`, children: [_jsxs("div", { className: styles.toggleHeading, onClick: () => setShowMcpTokensList((prev) => !prev), onKeyDown: (e) => {
|
|
923
928
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
924
929
|
e.preventDefault();
|
|
925
930
|
setShowMcpTokensList((prev) => !prev);
|
|
926
931
|
}
|
|
927
|
-
}, role: "button", tabIndex: 0, title: showMcpTokensList ? 'Hide workspace tokens' : 'Show workspace tokens', children: [_jsx("label", { className: styles.label, children: "Your Tokens" }), showMcpTokensList ? _jsx(ChevronDown, { size: 14 }) : _jsx(ChevronRight, { size: 14 })] }), showMcpTokensList && (_jsxs(_Fragment, { children: [_jsx("div", { className: `${styles.settingDescription} ${styles.marginTop12}`, children: "Manage tokens created for this workspace." }), mcpTokensLoading ? (_jsx("p", { className: styles.settingHelper, children: "Loading tokens\u2026" })) : mcpTokensError ? (_jsxs("div", { className: styles.errorMessage, children: [_jsx(AlertTriangle, { size: 14 }), mcpTokensError] })) : mcpTokens.length === 0 ? (_jsx("p", { className: styles.settingHelper, children: "No MCP tokens yet." })) : (_jsx("div", { className: styles.settingGroup, children: sortedMcpTokens.map((token) => (_jsxs("div", { className: `${styles.settingsItem} ${styles.marginTop12}`, style: {
|
|
932
|
+
}, role: "button", tabIndex: 0, title: showMcpTokensList ? 'Hide workspace tokens' : 'Show workspace tokens', children: [_jsx("label", { className: styles.label, children: "Your Tokens" }), showMcpTokensList ? _jsx(ChevronDown, { size: 14 }) : _jsx(ChevronRight, { size: 14 })] }), showMcpTokensList && (_jsxs(_Fragment, { children: [_jsx("div", { className: `${styles.settingDescription} ${styles.marginTop12}`, children: "Manage tokens created for this workspace." }), mcpTokenListNotice && (_jsxs("div", { className: `${mcpTokenListNotice.type === 'success' ? styles.successMessage : styles.errorMessage} ${styles.marginTop12}`, children: [mcpTokenListNotice.type === 'success' ? _jsx(Check, { size: 14 }) : _jsx(AlertTriangle, { size: 14 }), mcpTokenListNotice.message] })), mcpTokensLoading ? (_jsx("p", { className: styles.settingHelper, children: "Loading tokens\u2026" })) : mcpTokensError ? (_jsxs("div", { className: styles.errorMessage, children: [_jsx(AlertTriangle, { size: 14 }), mcpTokensError] })) : mcpTokens.length === 0 ? (_jsx("p", { className: styles.settingHelper, children: "No MCP tokens yet." })) : (_jsx("div", { className: styles.settingGroup, children: sortedMcpTokens.map((token) => (_jsxs("div", { className: `${styles.settingsItem} ${styles.marginTop12}`, style: {
|
|
928
933
|
padding: '14px 16px',
|
|
929
934
|
borderRadius: '12px',
|
|
930
935
|
border: '1px solid var(--border-primary, rgba(255, 255, 255, 0.1))',
|
|
931
936
|
background: 'rgba(255, 255, 255, 0.03)'
|
|
932
|
-
}, children: [_jsxs("div", { className: styles.settingLabelGroup, children: [_jsxs("div", { className: styles.labelGroupFlex, children: [_jsx("label", { className: styles.settingLabel, children: token.name }), _jsx("span", { className: `${styles.configBadge} ${token.status === 'revoked' ? styles.configBadgeRevoked : token.status === 'expired' ? styles.configBadgeExpired : styles.configBadgeActive}`, children: token.status })] }), _jsx("span", { className: styles.settingDescription, style: { fontFamily: '"JetBrains Mono", "Fira Code", monospace' }, children: token.tokenPrefix }), _jsxs("span", { className: styles.settingDescription, children: ["Scopes: ", token.scopes.join(', ')] }), _jsxs("span", { className: styles.settingDescription, children: ["Created ", new Date(token.createdAt).toLocaleDateString(), token.lastUsedAt ? ` · Last used ${new Date(token.lastUsedAt).toLocaleString()}` : ' · Never used'] })] }), _jsxs("div", { style: { display: 'flex', gap: '8px', flexWrap: 'wrap', justifyContent: 'flex-end' }, children: [token.status
|
|
937
|
+
}, children: [_jsxs("div", { className: styles.settingLabelGroup, children: [_jsxs("div", { className: styles.labelGroupFlex, children: [_jsx("label", { className: styles.settingLabel, children: token.name }), _jsx("span", { className: `${styles.configBadge} ${token.status === 'revoked' ? styles.configBadgeRevoked : token.status === 'expired' ? styles.configBadgeExpired : styles.configBadgeActive}`, children: token.status })] }), _jsx("span", { className: styles.settingDescription, style: { fontFamily: '"JetBrains Mono", "Fira Code", monospace' }, children: token.tokenPrefix }), _jsxs("span", { className: styles.settingDescription, children: ["Scopes: ", token.scopes.join(', ')] }), _jsxs("span", { className: styles.settingDescription, children: ["Created ", new Date(token.createdAt).toLocaleDateString(), token.lastUsedAt ? ` · Last used ${new Date(token.lastUsedAt).toLocaleString()}` : ' · Never used'] })] }), _jsxs("div", { style: { display: 'flex', gap: '8px', flexWrap: 'wrap', justifyContent: 'flex-end' }, children: [token.status === 'active' && (_jsx("button", { className: styles.copyBtn, onClick: () => void handleMcpTokenAction(token.id, 'regenerate'), disabled: mcpActionBusyId === `regenerate:${token.id}`, children: "Regenerate" })), token.status === 'active' && (_jsx("button", { className: styles.copyBtn, onClick: () => void handleMcpTokenAction(token.id, 'revoke'), disabled: mcpActionBusyId === `revoke:${token.id}`, children: "Revoke" })), token.status !== 'active' && (_jsx("button", { className: styles.copyBtn, onClick: () => void handleMcpTokenAction(token.id, 'delete'), disabled: mcpActionBusyId === `delete:${token.id}`, children: "Delete" }))] })] }, token.id))) }))] }))] })] })) })), showLocalMcp && (_jsxs(_Fragment, { children: [_jsx("div", { className: `${styles.settingGroup} ${styles.marginTop16}`, children: _jsxs("div", { className: styles.settingLabelGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "Local MCP" }), _jsx("span", { className: styles.settingDescription, children: "Local MCP connects through your local Taskforce install and does not require a cloud access token. Use this for Codex, Claude Code CLI, Gemini CLI, and similar local MCP clients." })] }) }), _jsxs("div", { className: `${styles.codeBlockWrapper} ${styles.codeBlockWrapperCustom}`, children: [_jsxs("div", { className: styles.codeHeader, children: [_jsx("span", { className: styles.codeLabel, children: "Local MCP Configuration" }), _jsxs("div", { className: styles.codeHeaderActions, children: [_jsx("select", { className: styles.settingInput, value: selectedMcpClient, onChange: (e) => setSelectedMcpClient(e.target.value), "aria-label": "MCP client", style: { width: 'auto', minWidth: '170px', padding: '6px 12px', fontSize: '12px', borderRadius: '8px' }, children: MCP_CLIENT_OPTIONS.map((option) => (_jsx("option", { value: option.id, disabled: option.disabled, children: option.label }, option.id))) }), _jsx("button", { className: `${styles.copyBtn} ${copiedConfig === 'full' ? styles.copyBtnActive : ''}`, onClick: () => handleCopyConfig('full'), title: "Copy full configuration file", children: copiedConfig === 'full' ? _jsx(Check, { size: 14 }) : _jsx(Copy, { size: 14 }) })] })] }), _jsx("pre", { className: styles.codeBlock, children: _jsx("code", { children: localMcpServerConfig
|
|
933
938
|
? renderMcpConfigBlock(localMcpServer.serverId, localMcpServerConfig, localClientIntegration.rootKey || 'mcpServers', localClientIntegration.wrapperKeys || [])
|
|
934
|
-
: renderTextConfigBlock(localClientIntegration.renderedText || '') }) })] }), _jsxs("div", { className: `${styles.codeBlockWrapper} ${styles.marginTop12}`, children: [_jsx("div", { className: styles.codeHeader, children: _jsx("span", { className: styles.codeLabel, children: localClientIntegration.instructionLabel }) }),
|
|
939
|
+
: renderTextConfigBlock(localClientIntegration.renderedText || '') }) })] }), _jsxs("div", { className: `${styles.codeBlockWrapper} ${styles.marginTop12}`, children: [_jsx("div", { className: styles.codeHeader, children: _jsx("span", { className: styles.codeLabel, children: localClientIntegration.instructionLabel }) }), _jsxs("div", { style: { padding: '16px 20px' }, children: [_jsx("div", { className: styles.settingDescription, children: localClientIntegration.instructionText }), renderMcpProfilePrompt()] })] }), _jsx("div", { className: `${styles.settingGroup} ${styles.marginTop12}`, children: _jsxs("div", { className: styles.toggleHeading, onClick: () => setShowAdvancedMcp((prev) => !prev), onKeyDown: (e) => {
|
|
935
940
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
936
941
|
e.preventDefault();
|
|
937
942
|
setShowAdvancedMcp((prev) => !prev);
|