@parhelia/core 0.1.11873 → 0.1.11955
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/agents-view/AgentsInbox.d.ts +1 -1
- package/dist/agents-view/AgentsInbox.js +15 -2
- package/dist/agents-view/AgentsInbox.js.map +1 -1
- package/dist/agents-view/AgentsSidebar.d.ts +20 -0
- package/dist/agents-view/AgentsSidebar.js +21 -0
- package/dist/agents-view/AgentsSidebar.js.map +1 -0
- package/dist/agents-view/AgentsView.d.ts +6 -7
- package/dist/agents-view/AgentsView.js +63 -25
- package/dist/agents-view/AgentsView.js.map +1 -1
- package/dist/agents-view/AgentsWorkspaceView.d.ts +2 -6
- package/dist/agents-view/AgentsWorkspaceView.js +242 -112
- package/dist/agents-view/AgentsWorkspaceView.js.map +1 -1
- package/dist/components/ui/context-menu.js +24 -9
- package/dist/components/ui/context-menu.js.map +1 -1
- package/dist/components/ui/select.js +1 -1
- package/dist/components/ui/select.js.map +1 -1
- package/dist/config/config.js +15 -11
- package/dist/config/config.js.map +1 -1
- package/dist/editor/ContentTree.js +2 -2
- package/dist/editor/ContentTree.js.map +1 -1
- package/dist/editor/ContextMenu.js +11 -5
- package/dist/editor/ContextMenu.js.map +1 -1
- package/dist/editor/FieldListField.js +1 -1
- package/dist/editor/FieldListField.js.map +1 -1
- package/dist/editor/MainLayout.js.map +1 -1
- package/dist/editor/MobileLayout.js +19 -9
- package/dist/editor/MobileLayout.js.map +1 -1
- package/dist/editor/ai/AgentStatusBadge.d.ts +1 -1
- package/dist/editor/ai/AgentStatusBadge.js +18 -2
- package/dist/editor/ai/AgentStatusBadge.js.map +1 -1
- package/dist/editor/ai/AgentTerminal.js +342 -55
- package/dist/editor/ai/AgentTerminal.js.map +1 -1
- package/dist/editor/ai/AiResponseMessage.js +46 -4
- package/dist/editor/ai/AiResponseMessage.js.map +1 -1
- package/dist/editor/ai/ContextInfoBar.js +151 -5
- package/dist/editor/ai/ContextInfoBar.js.map +1 -1
- package/dist/editor/ai/EditOperationsPanel.d.ts +2 -1
- package/dist/editor/ai/EditOperationsPanel.js +6 -1
- package/dist/editor/ai/EditOperationsPanel.js.map +1 -1
- package/dist/editor/ai/dialogs/AgentDialogHandler.js +64 -15
- package/dist/editor/ai/dialogs/AgentDialogHandler.js.map +1 -1
- package/dist/editor/ai/dialogs/QuestionnaireInline.js +111 -20
- package/dist/editor/ai/dialogs/QuestionnaireInline.js.map +1 -1
- package/dist/editor/ai/dialogs/agentDialogTypes.d.ts +24 -0
- package/dist/editor/ai/dialogs/agentDialogTypes.js.map +1 -1
- package/dist/editor/ai/useAgentStatus.d.ts +1 -0
- package/dist/editor/ai/useAgentStatus.js +74 -29
- package/dist/editor/ai/useAgentStatus.js.map +1 -1
- package/dist/editor/client/EditorShell.js +72 -8
- package/dist/editor/client/EditorShell.js.map +1 -1
- package/dist/editor/client/hooks/useQuota.d.ts +7 -0
- package/dist/editor/client/hooks/useQuota.js.map +1 -1
- package/dist/editor/client/hooks/useSocketMessageHandler.js +10 -1
- package/dist/editor/client/hooks/useSocketMessageHandler.js.map +1 -1
- package/dist/editor/client/pageModelBuilder.js +3 -30
- package/dist/editor/client/pageModelBuilder.js.map +1 -1
- package/dist/editor/client/ui/EditorChrome.js +31 -1
- package/dist/editor/client/ui/EditorChrome.js.map +1 -1
- package/dist/editor/commands/componentCommands.js +106 -6
- package/dist/editor/commands/componentCommands.js.map +1 -1
- package/dist/editor/commands/itemCommands.d.ts +1 -0
- package/dist/editor/commands/itemCommands.js +28 -1
- package/dist/editor/commands/itemCommands.js.map +1 -1
- package/dist/editor/componentTreeHelper.js +22 -2
- package/dist/editor/componentTreeHelper.js.map +1 -1
- package/dist/editor/insertMenuItems.d.ts +4 -0
- package/dist/editor/insertMenuItems.js +66 -0
- package/dist/editor/insertMenuItems.js.map +1 -0
- package/dist/editor/menubar/toolbar-sections/UtilityControls.js +1 -1
- package/dist/editor/menubar/toolbar-sections/UtilityControls.js.map +1 -1
- package/dist/editor/page-editor-chrome/FrameMenus.js +8 -1
- package/dist/editor/page-editor-chrome/FrameMenus.js.map +1 -1
- package/dist/editor/page-editor-chrome/InlineEditor.js +25 -11
- package/dist/editor/page-editor-chrome/InlineEditor.js.map +1 -1
- package/dist/editor/page-editor-chrome/PlaceholderDropZone.js +32 -17
- package/dist/editor/page-editor-chrome/PlaceholderDropZone.js.map +1 -1
- package/dist/editor/page-editor-chrome/PlaceholderDropZones.js +17 -11
- package/dist/editor/page-editor-chrome/PlaceholderDropZones.js.map +1 -1
- package/dist/editor/page-viewer/EditorForm.js +6 -5
- package/dist/editor/page-viewer/EditorForm.js.map +1 -1
- package/dist/editor/page-viewer/PageViewerFrame.js +49 -1
- package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
- package/dist/editor/page-viewer/pageModelSkeletonBuilder.js +5 -0
- package/dist/editor/page-viewer/pageModelSkeletonBuilder.js.map +1 -1
- package/dist/editor/pageModel.d.ts +2 -0
- package/dist/editor/reviews/CreateReviewConfirmStep.d.ts +16 -0
- package/dist/editor/reviews/CreateReviewConfirmStep.js +37 -0
- package/dist/editor/reviews/CreateReviewConfirmStep.js.map +1 -0
- package/dist/editor/reviews/CreateReviewDetailsStep.d.ts +51 -0
- package/dist/editor/reviews/CreateReviewDetailsStep.js +121 -0
- package/dist/editor/reviews/CreateReviewDetailsStep.js.map +1 -0
- package/dist/editor/reviews/CreateReviewDialog.js +260 -173
- package/dist/editor/reviews/CreateReviewDialog.js.map +1 -1
- package/dist/editor/reviews/CreateReviewSuccessStep.d.ts +6 -0
- package/dist/editor/reviews/CreateReviewSuccessStep.js +8 -0
- package/dist/editor/reviews/CreateReviewSuccessStep.js.map +1 -0
- package/dist/editor/reviews/DecisionsMatrix.js +96 -25
- package/dist/editor/reviews/DecisionsMatrix.js.map +1 -1
- package/dist/editor/reviews/MultiReviewManager.js +25 -3
- package/dist/editor/reviews/MultiReviewManager.js.map +1 -1
- package/dist/editor/reviews/PagesPanel.js +31 -15
- package/dist/editor/reviews/PagesPanel.js.map +1 -1
- package/dist/editor/reviews/ReviewCard.js +13 -7
- package/dist/editor/reviews/ReviewCard.js.map +1 -1
- package/dist/editor/reviews/ReviewDetail.js +2 -2
- package/dist/editor/reviews/ReviewDetail.js.map +1 -1
- package/dist/editor/reviews/ReviewsList.js +7 -3
- package/dist/editor/reviews/ReviewsList.js.map +1 -1
- package/dist/editor/services/agentService.d.ts +14 -1
- package/dist/editor/services/agentService.js +27 -1
- package/dist/editor/services/agentService.js.map +1 -1
- package/dist/editor/services/aiService.d.ts +39 -1
- package/dist/editor/services/aiService.js +12 -2
- package/dist/editor/services/aiService.js.map +1 -1
- package/dist/editor/services/serviceHelper.d.ts +1 -1
- package/dist/editor/services/serviceHelper.js +2 -1
- package/dist/editor/services/serviceHelper.js.map +1 -1
- package/dist/editor/settings/About.js +1 -1
- package/dist/editor/settings/About.js.map +1 -1
- package/dist/editor/settings/QuotaInfo.js +202 -4
- package/dist/editor/settings/QuotaInfo.js.map +1 -1
- package/dist/editor/settings/panels/SearchConfigPanel.js +11 -13
- package/dist/editor/settings/panels/SearchConfigPanel.js.map +1 -1
- package/dist/editor/settings/status/useStartupChecks.js +2 -1
- package/dist/editor/settings/status/useStartupChecks.js.map +1 -1
- package/dist/editor/sidebar/ComponentTree.js +26 -20
- package/dist/editor/sidebar/ComponentTree.js.map +1 -1
- package/dist/editor/sidebar/MobileWorkspacePopover.d.ts +16 -0
- package/dist/editor/sidebar/MobileWorkspacePopover.js +35 -0
- package/dist/editor/sidebar/MobileWorkspacePopover.js.map +1 -0
- package/dist/editor/sidebar/NavigationSidebar.js +30 -14
- package/dist/editor/sidebar/NavigationSidebar.js.map +1 -1
- package/dist/editor/ui/ItemNameDialogNew.js +8 -8
- package/dist/editor/ui/ItemNameDialogNew.js.map +1 -1
- package/dist/editor/ui/SharedFolderSelectorDialog.d.ts +11 -0
- package/dist/editor/ui/SharedFolderSelectorDialog.js +79 -0
- package/dist/editor/ui/SharedFolderSelectorDialog.js.map +1 -0
- package/dist/editor/ui/SimpleTabs.js +1 -1
- package/dist/editor/ui/SimpleTabs.js.map +1 -1
- package/dist/editor/ui/Splitter.js +4 -2
- package/dist/editor/ui/Splitter.js.map +1 -1
- package/dist/editor/ui/TreeListSelector.d.ts +2 -1
- package/dist/editor/ui/TreeListSelector.js +2 -2
- package/dist/editor/ui/TreeListSelector.js.map +1 -1
- package/dist/editor/utils.js +42 -0
- package/dist/editor/utils.js.map +1 -1
- package/dist/editor/views/EditorSlot.js +7 -8
- package/dist/editor/views/EditorSlot.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/setup/wizard/steps/ImportModelDialog.js +24 -22
- package/dist/setup/wizard/steps/ImportModelDialog.js.map +1 -1
- package/dist/splash-screen/NewPage.js +2 -2
- package/dist/splash-screen/NewPage.js.map +1 -1
- package/dist/splash-screen/RecentPages.js +1 -1
- package/dist/splash-screen/RecentPages.js.map +1 -1
- package/dist/task-board/TaskBoardWorkspace.d.ts +1 -0
- package/dist/task-board/TaskBoardWorkspace.js +1094 -0
- package/dist/task-board/TaskBoardWorkspace.js.map +1 -0
- package/dist/task-board/components/AddDependencyDialog.d.ts +8 -0
- package/dist/task-board/components/AddDependencyDialog.js +53 -0
- package/dist/task-board/components/AddDependencyDialog.js.map +1 -0
- package/dist/task-board/components/AssignAgentDialog.d.ts +7 -0
- package/dist/task-board/components/AssignAgentDialog.js +96 -0
- package/dist/task-board/components/AssignAgentDialog.js.map +1 -0
- package/dist/task-board/components/CommentsList.d.ts +3 -0
- package/dist/task-board/components/CommentsList.js +36 -0
- package/dist/task-board/components/CommentsList.js.map +1 -0
- package/dist/task-board/components/CreateProjectDialog.d.ts +7 -0
- package/dist/task-board/components/CreateProjectDialog.js +175 -0
- package/dist/task-board/components/CreateProjectDialog.js.map +1 -0
- package/dist/task-board/components/CreateTaskDialog.d.ts +7 -0
- package/dist/task-board/components/CreateTaskDialog.js +76 -0
- package/dist/task-board/components/CreateTaskDialog.js.map +1 -0
- package/dist/task-board/components/ProjectAgentsPanel.d.ts +4 -0
- package/dist/task-board/components/ProjectAgentsPanel.js +159 -0
- package/dist/task-board/components/ProjectAgentsPanel.js.map +1 -0
- package/dist/task-board/components/ProjectDashboard.d.ts +25 -0
- package/dist/task-board/components/ProjectDashboard.js +91 -0
- package/dist/task-board/components/ProjectDashboard.js.map +1 -0
- package/dist/task-board/components/ProjectList.d.ts +7 -0
- package/dist/task-board/components/ProjectList.js +74 -0
- package/dist/task-board/components/ProjectList.js.map +1 -0
- package/dist/task-board/components/ProjectSettingsDialog.d.ts +8 -0
- package/dist/task-board/components/ProjectSettingsDialog.js +146 -0
- package/dist/task-board/components/ProjectSettingsDialog.js.map +1 -0
- package/dist/task-board/components/TaskAgentPanel.d.ts +10 -0
- package/dist/task-board/components/TaskAgentPanel.js +42 -0
- package/dist/task-board/components/TaskAgentPanel.js.map +1 -0
- package/dist/task-board/components/TaskAssigneePicker.d.ts +12 -0
- package/dist/task-board/components/TaskAssigneePicker.js +115 -0
- package/dist/task-board/components/TaskAssigneePicker.js.map +1 -0
- package/dist/task-board/components/TaskBoardTitlebar.d.ts +1 -0
- package/dist/task-board/components/TaskBoardTitlebar.js +60 -0
- package/dist/task-board/components/TaskBoardTitlebar.js.map +1 -0
- package/dist/task-board/components/TaskCard.d.ts +9 -0
- package/dist/task-board/components/TaskCard.js +24 -0
- package/dist/task-board/components/TaskCard.js.map +1 -0
- package/dist/task-board/components/TaskDetailDialog.d.ts +11 -0
- package/dist/task-board/components/TaskDetailDialog.js +8 -0
- package/dist/task-board/components/TaskDetailDialog.js.map +1 -0
- package/dist/task-board/components/TaskDetailPanel.d.ts +13 -0
- package/dist/task-board/components/TaskDetailPanel.js +322 -0
- package/dist/task-board/components/TaskDetailPanel.js.map +1 -0
- package/dist/task-board/components/TaskRow.d.ts +9 -0
- package/dist/task-board/components/TaskRow.js +25 -0
- package/dist/task-board/components/TaskRow.js.map +1 -0
- package/dist/task-board/index.d.ts +15 -0
- package/dist/task-board/index.js +18 -0
- package/dist/task-board/index.js.map +1 -0
- package/dist/task-board/services/taskService.d.ts +52 -0
- package/dist/task-board/services/taskService.js +74 -0
- package/dist/task-board/services/taskService.js.map +1 -0
- package/dist/task-board/taskAgentConfig.d.ts +7 -0
- package/dist/task-board/taskAgentConfig.js +43 -0
- package/dist/task-board/taskAgentConfig.js.map +1 -0
- package/dist/task-board/taskAgentLink.d.ts +2 -0
- package/dist/task-board/taskAgentLink.js +35 -0
- package/dist/task-board/taskAgentLink.js.map +1 -0
- package/dist/task-board/taskBoardNavStore.d.ts +35 -0
- package/dist/task-board/taskBoardNavStore.js +42 -0
- package/dist/task-board/taskBoardNavStore.js.map +1 -0
- package/dist/task-board/taskExecutionStatus.d.ts +12 -0
- package/dist/task-board/taskExecutionStatus.js +96 -0
- package/dist/task-board/taskExecutionStatus.js.map +1 -0
- package/dist/task-board/taskStatus.d.ts +2 -0
- package/dist/task-board/taskStatus.js +26 -0
- package/dist/task-board/taskStatus.js.map +1 -0
- package/dist/task-board/types.d.ts +169 -0
- package/dist/task-board/types.js +2 -0
- package/dist/task-board/types.js.map +1 -0
- package/dist/task-board/utils/projectHierarchy.d.ts +13 -0
- package/dist/task-board/utils/projectHierarchy.js +34 -0
- package/dist/task-board/utils/projectHierarchy.js.map +1 -0
- package/dist/task-board/views/KanbanView.d.ts +14 -0
- package/dist/task-board/views/KanbanView.js +136 -0
- package/dist/task-board/views/KanbanView.js.map +1 -0
- package/dist/task-board/views/ListView.d.ts +13 -0
- package/dist/task-board/views/ListView.js +74 -0
- package/dist/task-board/views/ListView.js.map +1 -0
- package/dist/task-board/views/PlanningView.d.ts +7 -0
- package/dist/task-board/views/PlanningView.js +112 -0
- package/dist/task-board/views/PlanningView.js.map +1 -0
- package/package.json +1 -1
|
@@ -3,20 +3,17 @@ import { useState, useEffect, useMemo } from "react";
|
|
|
3
3
|
import { Dialog, DialogContent } from "../../components/ui/dialog";
|
|
4
4
|
import { StyledDialogTitle } from "../../components/ui/styled-dialog-title";
|
|
5
5
|
import { Button } from "../../components/ui/button";
|
|
6
|
-
import {
|
|
7
|
-
import { Label } from "../../components/ui/label";
|
|
8
|
-
import { Checkbox } from "../../components/ui/checkbox";
|
|
9
|
-
import { Switch } from "../../components/ui/switch";
|
|
10
|
-
import { Plus, X, Loader2, ChevronRight, ChevronLeft, ChevronDown, Settings2, ClipboardCheck, AlertTriangle, } from "lucide-react";
|
|
6
|
+
import { Loader2, ClipboardCheck, MailCheck, CheckCircle2 } from "lucide-react";
|
|
11
7
|
import { useEditContext } from "../client/editContext";
|
|
12
|
-
import { Splitter } from "../ui/Splitter";
|
|
13
|
-
import { SimpleIconButton } from "../ui/SimpleIconButton";
|
|
14
|
-
import { LanguageSelector } from "../../components/ui/LanguageSelector";
|
|
15
|
-
import { PreconfiguredReviewerSelector } from "./PreconfiguredReviewerSelector";
|
|
16
|
-
import { TreeListSelector } from "../ui/TreeListSelector";
|
|
17
8
|
import DialogButtons from "../ui/DialogButtons";
|
|
9
|
+
import { CreateReviewDetailsStep } from "./CreateReviewDetailsStep";
|
|
10
|
+
import { CreateReviewConfirmStep } from "./CreateReviewConfirmStep";
|
|
11
|
+
import { CreateReviewSuccessStep } from "./CreateReviewSuccessStep";
|
|
12
|
+
import { loadAiProfiles } from "../services/aiService";
|
|
13
|
+
import { awaitAgentResponse, closeAgent, startAgent, } from "../services/agentService";
|
|
18
14
|
export function CreateReviewDialog({ open, onOpenChange, onCreated, initialItems, }) {
|
|
19
15
|
const editContext = useEditContext();
|
|
16
|
+
const [step, setStep] = useState("details");
|
|
20
17
|
const [title, setTitle] = useState("");
|
|
21
18
|
const [language, setLanguage] = useState(editContext?.currentItemDescriptor?.language || "en");
|
|
22
19
|
const [languageMode, setLanguageMode] = useState("single");
|
|
@@ -41,6 +38,10 @@ export function CreateReviewDialog({ open, onOpenChange, onCreated, initialItems
|
|
|
41
38
|
const [selectedInTree, setSelectedInTree] = useState([]);
|
|
42
39
|
const [selectedFromList, setSelectedFromList] = useState([]);
|
|
43
40
|
const [advancedSettingsOpen, setAdvancedSettingsOpen] = useState(false);
|
|
41
|
+
const [createdReviewId, setCreatedReviewId] = useState(null);
|
|
42
|
+
const [sentInvitationCount, setSentInvitationCount] = useState(0);
|
|
43
|
+
const [sentInvitationEmails, setSentInvitationEmails] = useState([]);
|
|
44
|
+
const [isGeneratingTitle, setIsGeneratingTitle] = useState(false);
|
|
44
45
|
const CONTENT_ROOT_ID = "0de95ae4-41ab-4d01-9eb0-67441b7c2450"; // /sitecore/content
|
|
45
46
|
// Memoize rootItemIds to prevent unnecessary re-renders of ContentTree
|
|
46
47
|
const rootItemIds = useMemo(() => [CONTENT_ROOT_ID], []);
|
|
@@ -90,8 +91,10 @@ export function CreateReviewDialog({ open, onOpenChange, onCreated, initialItems
|
|
|
90
91
|
// This prevents resetting user changes (like includeSubitems toggles) when context changes
|
|
91
92
|
const initializeItems = async () => {
|
|
92
93
|
let currentDescriptor = editContext.currentItemDescriptor;
|
|
93
|
-
// If the descriptor is missing name or path, fetch it from the server
|
|
94
|
-
if ((!currentDescriptor.name ||
|
|
94
|
+
// If the descriptor is missing name, display name, or path, fetch it from the server
|
|
95
|
+
if ((!currentDescriptor.name ||
|
|
96
|
+
!currentDescriptor.displayName ||
|
|
97
|
+
!currentDescriptor.path) &&
|
|
95
98
|
editContext.itemsRepository) {
|
|
96
99
|
try {
|
|
97
100
|
const stubs = await editContext.itemsRepository.getItemsStubs([
|
|
@@ -101,6 +104,7 @@ export function CreateReviewDialog({ open, onOpenChange, onCreated, initialItems
|
|
|
101
104
|
currentDescriptor = {
|
|
102
105
|
...currentDescriptor,
|
|
103
106
|
name: stubs[0].name || currentDescriptor.name,
|
|
107
|
+
displayName: stubs[0].displayName || currentDescriptor.displayName,
|
|
104
108
|
path: stubs[0].path || currentDescriptor.path,
|
|
105
109
|
};
|
|
106
110
|
}
|
|
@@ -111,8 +115,8 @@ export function CreateReviewDialog({ open, onOpenChange, onCreated, initialItems
|
|
|
111
115
|
}
|
|
112
116
|
let itemsToSet;
|
|
113
117
|
if (initialItems) {
|
|
114
|
-
// Fetch missing names/paths for initial items as well
|
|
115
|
-
const itemsToFetch = initialItems.filter((i) => !i.name || !i.path);
|
|
118
|
+
// Fetch missing names/display names/paths for initial items as well
|
|
119
|
+
const itemsToFetch = initialItems.filter((i) => !i.name || !i.displayName || !i.path);
|
|
116
120
|
if (itemsToFetch.length > 0 && editContext.itemsRepository) {
|
|
117
121
|
try {
|
|
118
122
|
const stubs = await editContext.itemsRepository.getItemsStubs(itemsToFetch);
|
|
@@ -123,6 +127,7 @@ export function CreateReviewDialog({ open, onOpenChange, onCreated, initialItems
|
|
|
123
127
|
descriptor: {
|
|
124
128
|
...i,
|
|
125
129
|
name: stub?.name || i.name,
|
|
130
|
+
displayName: stub?.displayName || i.displayName,
|
|
126
131
|
path: stub?.path || i.path,
|
|
127
132
|
},
|
|
128
133
|
includeSubitems: false,
|
|
@@ -167,6 +172,119 @@ export function CreateReviewDialog({ open, onOpenChange, onCreated, initialItems
|
|
|
167
172
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
168
173
|
return emailRegex.test(email);
|
|
169
174
|
};
|
|
175
|
+
const extractReviewTitleFromAgentResponse = (content) => {
|
|
176
|
+
if (!content)
|
|
177
|
+
return "";
|
|
178
|
+
const fencedTitleMatch = content.match(/```(?:suggestion|title)\s*\n([\s\S]*?)```/i);
|
|
179
|
+
const fencedGenericMatch = content.match(/```\s*\n([\s\S]*?)```/);
|
|
180
|
+
const raw = (fencedTitleMatch?.[1] || fencedGenericMatch?.[1] || content)
|
|
181
|
+
.trim()
|
|
182
|
+
.replace(/^["']|["']$/g, "");
|
|
183
|
+
if (!raw)
|
|
184
|
+
return "";
|
|
185
|
+
return raw.split("\n")[0]?.trim() || "";
|
|
186
|
+
};
|
|
187
|
+
const buildReviewTitleSuggestionPrompt = () => {
|
|
188
|
+
const languageScope = languageMode === "all"
|
|
189
|
+
? "all languages"
|
|
190
|
+
: languageMode === "multiple"
|
|
191
|
+
? selectedLanguages.join(", ")
|
|
192
|
+
: language;
|
|
193
|
+
const itemNames = items
|
|
194
|
+
.slice(0, 5)
|
|
195
|
+
.map((item) => item.descriptor.displayName ||
|
|
196
|
+
item.descriptor.name ||
|
|
197
|
+
item.descriptor.path ||
|
|
198
|
+
item.descriptor.id)
|
|
199
|
+
.filter(Boolean)
|
|
200
|
+
.join(", ");
|
|
201
|
+
const reviewerNames = reviewers
|
|
202
|
+
.slice(0, 3)
|
|
203
|
+
.map((reviewer) => reviewer.name || reviewer.email)
|
|
204
|
+
.filter(Boolean)
|
|
205
|
+
.join(", ");
|
|
206
|
+
return `Generate a concise review name for a Sitecore content review.
|
|
207
|
+
|
|
208
|
+
Context:
|
|
209
|
+
- Language scope: ${languageScope}
|
|
210
|
+
- Items: ${itemNames || "N/A"}
|
|
211
|
+
- Number of reviewers: ${reviewers.length}
|
|
212
|
+
- First reviewers: ${reviewerNames || "N/A"}
|
|
213
|
+
- Includes subitems: ${items.some((x) => x.includeSubitems) ? "yes" : "no"}
|
|
214
|
+
|
|
215
|
+
Rules:
|
|
216
|
+
- Return a short, clear title (4-10 words).
|
|
217
|
+
- Do not use quotes.
|
|
218
|
+
- Do not include prefixes like "Review:".
|
|
219
|
+
- Output ONLY the title inside a \`\`\`suggestion fenced code block.
|
|
220
|
+
|
|
221
|
+
Example:
|
|
222
|
+
\`\`\`suggestion
|
|
223
|
+
Homepage and Navigation Content Review
|
|
224
|
+
\`\`\``;
|
|
225
|
+
};
|
|
226
|
+
const generateReviewTitleSuggestion = async () => {
|
|
227
|
+
if (title.trim())
|
|
228
|
+
return null;
|
|
229
|
+
if (!editContext?.addSocketMessageListener || !editContext.sessionId) {
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
const newAgentId = crypto.randomUUID();
|
|
233
|
+
setIsGeneratingTitle(true);
|
|
234
|
+
try {
|
|
235
|
+
const profiles = await loadAiProfiles(editContext.currentItemDescriptor);
|
|
236
|
+
if (!profiles || profiles.length === 0) {
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
const configuredProfileId = editContext.parheliaSettings?.commentResolveProfileId;
|
|
240
|
+
const selectedProfile = profiles.find((profile) => configuredProfileId &&
|
|
241
|
+
profile.id.toLowerCase() === configuredProfileId.toLowerCase()) || profiles[0];
|
|
242
|
+
if (!selectedProfile)
|
|
243
|
+
return null;
|
|
244
|
+
await startAgent({
|
|
245
|
+
agentId: newAgentId,
|
|
246
|
+
message: buildReviewTitleSuggestionPrompt(),
|
|
247
|
+
sessionId: editContext.sessionId,
|
|
248
|
+
profileId: selectedProfile.id,
|
|
249
|
+
mode: "autonomous",
|
|
250
|
+
context: {
|
|
251
|
+
items: items.map((item) => ({
|
|
252
|
+
id: item.descriptor.id,
|
|
253
|
+
language: item.descriptor.language,
|
|
254
|
+
version: item.descriptor.version,
|
|
255
|
+
name: item.descriptor.name,
|
|
256
|
+
path: item.descriptor.path,
|
|
257
|
+
})),
|
|
258
|
+
additionalData: {
|
|
259
|
+
intent: "review-title-suggestion",
|
|
260
|
+
reviewerCount: reviewers.length,
|
|
261
|
+
},
|
|
262
|
+
},
|
|
263
|
+
});
|
|
264
|
+
const result = await awaitAgentResponse({
|
|
265
|
+
agentId: newAgentId,
|
|
266
|
+
addSocketMessageListener: editContext.addSocketMessageListener,
|
|
267
|
+
timeout: 45000,
|
|
268
|
+
});
|
|
269
|
+
if (!result.success)
|
|
270
|
+
return null;
|
|
271
|
+
const extractedTitle = extractReviewTitleFromAgentResponse(result.content);
|
|
272
|
+
return extractedTitle || null;
|
|
273
|
+
}
|
|
274
|
+
catch (err) {
|
|
275
|
+
console.error("Failed to generate review title suggestion:", err);
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
finally {
|
|
279
|
+
setIsGeneratingTitle(false);
|
|
280
|
+
try {
|
|
281
|
+
await closeAgent(newAgentId);
|
|
282
|
+
}
|
|
283
|
+
catch (err) {
|
|
284
|
+
console.error("Failed to close review title suggestion agent:", err);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
};
|
|
170
288
|
const emailAlreadyExists = (email) => {
|
|
171
289
|
return reviewers.some((r) => r.email.toLowerCase() === email.toLowerCase());
|
|
172
290
|
};
|
|
@@ -198,40 +316,80 @@ export function CreateReviewDialog({ open, onOpenChange, onCreated, initialItems
|
|
|
198
316
|
const removeItem = (index) => {
|
|
199
317
|
setItems(items.filter((_, i) => i !== index));
|
|
200
318
|
};
|
|
201
|
-
const
|
|
202
|
-
|
|
319
|
+
const resetDialogState = () => {
|
|
320
|
+
setStep("details");
|
|
321
|
+
setTitle("");
|
|
322
|
+
setReviewers([]);
|
|
323
|
+
setItems([]);
|
|
324
|
+
setExpirationDays("");
|
|
325
|
+
setSecret("");
|
|
326
|
+
setSecretConfirm("");
|
|
327
|
+
setShowSecretFields(false);
|
|
328
|
+
setRequiredApprovals("1");
|
|
329
|
+
setUpdateWorkflowOnCompletion(false);
|
|
330
|
+
setShowErrors(false);
|
|
203
331
|
setError(null);
|
|
332
|
+
setLanguageMode("single");
|
|
333
|
+
setSelectedLanguages([
|
|
334
|
+
editContext?.currentItemDescriptor?.language || "en",
|
|
335
|
+
]);
|
|
336
|
+
setLanguage(editContext?.currentItemDescriptor?.language || "en");
|
|
337
|
+
setAdvancedSettingsOpen(false);
|
|
338
|
+
setSelectedInTree([]);
|
|
339
|
+
setSelectedFromList([]);
|
|
340
|
+
setNewReviewer({ name: "", email: "" });
|
|
341
|
+
setCreatedReviewId(null);
|
|
342
|
+
setSentInvitationCount(0);
|
|
343
|
+
setSentInvitationEmails([]);
|
|
344
|
+
setIsGeneratingTitle(false);
|
|
345
|
+
};
|
|
346
|
+
const validateForm = () => {
|
|
204
347
|
if (items.length === 0) {
|
|
205
|
-
|
|
206
|
-
return;
|
|
348
|
+
return "Please select at least one page/item";
|
|
207
349
|
}
|
|
208
350
|
if (reviewers.length === 0) {
|
|
209
|
-
|
|
210
|
-
return;
|
|
351
|
+
return "Please add at least one reviewer";
|
|
211
352
|
}
|
|
212
|
-
// Validate language selection based on mode
|
|
213
353
|
if (languageMode === "single" && !language) {
|
|
214
|
-
|
|
215
|
-
return;
|
|
354
|
+
return "Language is required";
|
|
216
355
|
}
|
|
217
356
|
if (languageMode === "multiple" && selectedLanguages.length === 0) {
|
|
218
|
-
|
|
219
|
-
return;
|
|
357
|
+
return "Please select at least one language";
|
|
220
358
|
}
|
|
221
359
|
if (showSecretFields && secret !== secretConfirm) {
|
|
222
|
-
|
|
223
|
-
return;
|
|
360
|
+
return "Secrets do not match";
|
|
224
361
|
}
|
|
225
|
-
// Validate RequiredApprovals
|
|
226
362
|
const requiredApprovalsNum = requiredApprovals
|
|
227
363
|
? parseInt(requiredApprovals, 10)
|
|
228
364
|
: 1;
|
|
229
365
|
if (isNaN(requiredApprovalsNum) || requiredApprovalsNum < 1) {
|
|
230
|
-
|
|
231
|
-
return;
|
|
366
|
+
return "Required Approvals must be at least 1";
|
|
232
367
|
}
|
|
233
368
|
if (requiredApprovalsNum > reviewers.length) {
|
|
234
|
-
|
|
369
|
+
return `Required Approvals (${requiredApprovalsNum}) cannot exceed the number of reviewers (${reviewers.length})`;
|
|
370
|
+
}
|
|
371
|
+
return null;
|
|
372
|
+
};
|
|
373
|
+
const handleProceedToConfirm = async () => {
|
|
374
|
+
setShowErrors(true);
|
|
375
|
+
setError(null);
|
|
376
|
+
const validationError = validateForm();
|
|
377
|
+
if (validationError) {
|
|
378
|
+
setError(validationError);
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
const suggestedTitle = await generateReviewTitleSuggestion();
|
|
382
|
+
if (suggestedTitle && !title.trim()) {
|
|
383
|
+
setTitle(suggestedTitle);
|
|
384
|
+
}
|
|
385
|
+
setStep("confirm");
|
|
386
|
+
};
|
|
387
|
+
const handleCreate = async () => {
|
|
388
|
+
setShowErrors(true);
|
|
389
|
+
setError(null);
|
|
390
|
+
const validationError = validateForm();
|
|
391
|
+
if (validationError) {
|
|
392
|
+
setError(validationError);
|
|
235
393
|
return;
|
|
236
394
|
}
|
|
237
395
|
setLoading(true);
|
|
@@ -257,6 +415,9 @@ export function CreateReviewDialog({ open, onOpenChange, onCreated, initialItems
|
|
|
257
415
|
// Single language mode - use legacy language field for backward compatibility
|
|
258
416
|
languages = [language];
|
|
259
417
|
}
|
|
418
|
+
const requiredApprovalsNum = requiredApprovals
|
|
419
|
+
? parseInt(requiredApprovals, 10)
|
|
420
|
+
: 1;
|
|
260
421
|
const request = {
|
|
261
422
|
title: title || undefined,
|
|
262
423
|
language: languageMode === "single" ? language : undefined, // Keep for backward compatibility
|
|
@@ -271,34 +432,39 @@ export function CreateReviewDialog({ open, onOpenChange, onCreated, initialItems
|
|
|
271
432
|
const { createReview, getReviewStatus, sendInvitations } = await import("../services/reviewsService");
|
|
272
433
|
const result = await createReview(request);
|
|
273
434
|
if (result.data?.reviewId) {
|
|
435
|
+
setCreatedReviewId(result.data.reviewId);
|
|
274
436
|
// Get assignments to send invitations
|
|
275
437
|
const statusResult = await getReviewStatus(result.data.reviewId);
|
|
276
438
|
if (statusResult.data?.assignments) {
|
|
277
|
-
const
|
|
278
|
-
|
|
279
|
-
|
|
439
|
+
const assignmentsToInvite = statusResult.data.assignments.filter((a) => !a.invitationSentDate);
|
|
440
|
+
const assignmentIds = assignmentsToInvite.map((a) => a.assignmentId);
|
|
441
|
+
const reviewerEmails = Array.from(new Set(assignmentsToInvite.map((a) => a.reviewerEmail)));
|
|
280
442
|
if (assignmentIds.length > 0) {
|
|
281
|
-
await sendInvitations(assignmentIds);
|
|
443
|
+
const invitationResult = await sendInvitations(assignmentIds);
|
|
444
|
+
if (invitationResult.type !== "success") {
|
|
445
|
+
throw new Error(invitationResult.details ||
|
|
446
|
+
invitationResult.summary ||
|
|
447
|
+
"Failed to send invitation emails");
|
|
448
|
+
}
|
|
449
|
+
if (invitationResult.data &&
|
|
450
|
+
typeof invitationResult.data === "object" &&
|
|
451
|
+
"errors" in invitationResult.data &&
|
|
452
|
+
Array.isArray(invitationResult.data.errors) &&
|
|
453
|
+
invitationResult.data.errors.length > 0) {
|
|
454
|
+
const errorMessages = invitationResult.data.errors
|
|
455
|
+
.map((err) => err?.message || err?.Message || String(err))
|
|
456
|
+
.join("; ");
|
|
457
|
+
throw new Error(errorMessages || "Failed to send invitation emails");
|
|
458
|
+
}
|
|
282
459
|
}
|
|
460
|
+
setSentInvitationCount(assignmentIds.length);
|
|
461
|
+
setSentInvitationEmails(reviewerEmails);
|
|
462
|
+
}
|
|
463
|
+
else {
|
|
464
|
+
setSentInvitationCount(0);
|
|
465
|
+
setSentInvitationEmails([]);
|
|
283
466
|
}
|
|
284
|
-
|
|
285
|
-
// Reset form
|
|
286
|
-
setTitle("");
|
|
287
|
-
setReviewers([]);
|
|
288
|
-
setItems([]);
|
|
289
|
-
setExpirationDays("");
|
|
290
|
-
setSecret("");
|
|
291
|
-
setSecretConfirm("");
|
|
292
|
-
setShowSecretFields(false);
|
|
293
|
-
setRequiredApprovals("1");
|
|
294
|
-
setUpdateWorkflowOnCompletion(false);
|
|
295
|
-
setShowErrors(false);
|
|
296
|
-
setLanguageMode("single");
|
|
297
|
-
setSelectedLanguages([
|
|
298
|
-
editContext?.currentItemDescriptor?.language || "en",
|
|
299
|
-
]);
|
|
300
|
-
setLanguage(editContext?.currentItemDescriptor?.language || "en");
|
|
301
|
-
onOpenChange(false);
|
|
467
|
+
setStep("success");
|
|
302
468
|
}
|
|
303
469
|
else {
|
|
304
470
|
setError("Failed to create review");
|
|
@@ -314,8 +480,8 @@ export function CreateReviewDialog({ open, onOpenChange, onCreated, initialItems
|
|
|
314
480
|
const addToList = async () => {
|
|
315
481
|
const newItems = [...items];
|
|
316
482
|
const nodesToAdd = selectedInTree.filter((node) => !newItems.some((x) => x.descriptor.id === node.id));
|
|
317
|
-
// Fetch missing paths/names if needed
|
|
318
|
-
const nodesNeedingFetch = nodesToAdd.filter((node) => !node.path || !node.name);
|
|
483
|
+
// Fetch missing paths/names/display names if needed
|
|
484
|
+
const nodesNeedingFetch = nodesToAdd.filter((node) => !node.path || !node.name || !node.displayName);
|
|
319
485
|
if (nodesNeedingFetch.length > 0 && editContext?.itemsRepository) {
|
|
320
486
|
try {
|
|
321
487
|
const descriptorsToFetch = nodesNeedingFetch.map((node) => ({
|
|
@@ -333,6 +499,7 @@ export function CreateReviewDialog({ open, onOpenChange, onCreated, initialItems
|
|
|
333
499
|
language: node.language || language,
|
|
334
500
|
version: node.version || 1,
|
|
335
501
|
name: stub?.name || node.name || "",
|
|
502
|
+
displayName: stub?.displayName || node.displayName || "",
|
|
336
503
|
path: stub?.path || node.path || node.idPath || "",
|
|
337
504
|
},
|
|
338
505
|
includeSubitems: false,
|
|
@@ -349,6 +516,7 @@ export function CreateReviewDialog({ open, onOpenChange, onCreated, initialItems
|
|
|
349
516
|
language: node.language || language,
|
|
350
517
|
version: node.version || 1,
|
|
351
518
|
name: node.name || "",
|
|
519
|
+
displayName: node.displayName || "",
|
|
352
520
|
path: node.path || node.idPath || "",
|
|
353
521
|
},
|
|
354
522
|
includeSubitems: false,
|
|
@@ -365,6 +533,7 @@ export function CreateReviewDialog({ open, onOpenChange, onCreated, initialItems
|
|
|
365
533
|
language: node.language || language,
|
|
366
534
|
version: node.version || 1,
|
|
367
535
|
name: node.name || "",
|
|
536
|
+
displayName: node.displayName || "",
|
|
368
537
|
path: node.path || node.idPath || "",
|
|
369
538
|
},
|
|
370
539
|
includeSubitems: false,
|
|
@@ -387,10 +556,12 @@ export function CreateReviewDialog({ open, onOpenChange, onCreated, initialItems
|
|
|
387
556
|
language: item.language || language,
|
|
388
557
|
version: item.version || 1,
|
|
389
558
|
name: item.name || "",
|
|
559
|
+
displayName: item.displayName || "",
|
|
390
560
|
path: item.path || item.idPath || "",
|
|
391
561
|
};
|
|
392
|
-
// Fetch missing path/name if needed
|
|
393
|
-
if ((!item.path || !item.name
|
|
562
|
+
// Fetch missing path/name/display name if needed
|
|
563
|
+
if ((!item.path || !item.name || !item.displayName) &&
|
|
564
|
+
editContext?.itemsRepository) {
|
|
394
565
|
try {
|
|
395
566
|
const stubs = await editContext.itemsRepository.getItemsStubs([
|
|
396
567
|
{
|
|
@@ -403,6 +574,7 @@ export function CreateReviewDialog({ open, onOpenChange, onCreated, initialItems
|
|
|
403
574
|
itemDescriptor = {
|
|
404
575
|
...itemDescriptor,
|
|
405
576
|
name: stubs[0].name || itemDescriptor.name || "",
|
|
577
|
+
displayName: stubs[0].displayName || itemDescriptor.displayName || "",
|
|
406
578
|
path: stubs[0].path || itemDescriptor.path || "",
|
|
407
579
|
};
|
|
408
580
|
}
|
|
@@ -420,121 +592,36 @@ export function CreateReviewDialog({ open, onOpenChange, onCreated, initialItems
|
|
|
420
592
|
]);
|
|
421
593
|
}
|
|
422
594
|
};
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
}
|
|
455
|
-
}, onDoubleClick: () => {
|
|
456
|
-
setItems(items.filter((_, i) => i !== index));
|
|
457
|
-
setSelectedFromList([]);
|
|
458
|
-
}, children: [_jsxs("div", { className: "flex items-start justify-between gap-2", children: [_jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [_jsx("span", { className: "truncate text-sm font-semibold text-gray-900", children: item.descriptor.name ||
|
|
459
|
-
item.descriptor.path ||
|
|
460
|
-
item.descriptor.id }), item.descriptor.path && (_jsx("span", { className: "text-muted-foreground truncate text-[11px]", title: item.descriptor.path, children: item.descriptor.path })), _jsxs("div", { className: "mt-1 flex items-center gap-1.5", children: [_jsx("span", { className: "rounded bg-gray-100 px-1.5 py-0.5 text-[10px] font-medium text-gray-600 uppercase", children: item.descriptor.language }), _jsxs("span", { className: "text-muted-foreground text-[10px] font-medium", children: ["v", item.descriptor.version] })] })] }), _jsx(Button, { variant: "ghost", size: "sm", className: "text-muted-foreground hover:bg-destructive/10 hover:text-destructive h-7 w-7 shrink-0 p-0 opacity-0 transition-all group-hover:opacity-100", onClick: (e) => {
|
|
461
|
-
e.stopPropagation();
|
|
462
|
-
removeItem(index);
|
|
463
|
-
}, children: _jsx(X, { className: "h-4 w-4" }) })] }), _jsxs("div", { className: "flex items-center gap-2 border-t border-gray-100/50 pt-2", children: [_jsx(Switch, { id: `subpages-${item.descriptor.id}-${index}`, checked: item.includeSubitems, onCheckedChange: () => toggleSubitems(index), onClick: (e) => e.stopPropagation(), className: "scale-75" }), _jsx(Label, { htmlFor: `subpages-${item.descriptor.id}-${index}`, className: "cursor-pointer text-[11px] font-medium text-gray-500", onClick: (e) => e.stopPropagation(), children: "Include subitems" })] })] }, `${item.descriptor.id}-${index}`))) })) : (_jsxs("div", { className: "flex min-h-0 flex-1 flex-col items-center justify-center gap-3 p-8 text-center", children: [_jsx("div", { className: "rounded-full bg-gray-100/50 p-4 ring-8 ring-gray-50", children: _jsx(ClipboardCheck, { className: "h-6 w-6 text-gray-300", strokeWidth: 1 }) }), _jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-sm font-medium text-gray-500", children: "No items selected" }), _jsx("p", { className: "text-muted-foreground text-xs", children: "Browse or search to add items" })] })] }))] })),
|
|
464
|
-
},
|
|
465
|
-
], handleContent: (index) => index === 0 ? (_jsxs("div", { className: "flex flex-col items-center gap-1 rounded bg-gray-100 py-1", children: [_jsx(SimpleIconButton, { label: "Add", icon: _jsx(ChevronRight, { size: 14, strokeWidth: 1 }), onClick: addToList, disabled: selectedInTree.length === 0, showTooltip: false, className: "px-0" }), _jsx(SimpleIconButton, { label: "Remove", icon: _jsx(ChevronLeft, { size: 14, strokeWidth: 1 }), onClick: removeFromList, disabled: selectedFromList.length === 0, showTooltip: false, className: "px-0" })] })) : null }) }), showErrors && items.length === 0 && (_jsx("p", { className: "text-destructive text-xs font-medium", children: "Please select at least one page or item" }))] }), _jsx("div", { className: "border-t border-gray-100" }), _jsxs("div", { className: "flex flex-col gap-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("label", { className: "text-sm font-semibold text-gray-900", children: "Reviewers" }), reviewers.length > 0 && (_jsxs("span", { className: "bg-primary/10 text-primary rounded-full px-2.5 py-0.5 text-xs font-semibold", children: [reviewers.length, " added"] }))] }), _jsx("p", { className: "text-muted-foreground text-xs", children: "Add people who will review and approve the content." }), reviewers.length > 0 && (_jsx("div", { className: "flex flex-wrap gap-2.5", children: reviewers.map((reviewer, index) => (_jsxs("div", { className: "group hover:border-primary/30 flex items-center gap-2.5 rounded-full border border-gray-200 bg-white py-1.5 pr-2 pl-3.5 transition-all hover:shadow-sm", children: [_jsx("div", { className: "bg-primary/10 text-primary ring-primary/5 flex h-6 w-6 items-center justify-center rounded-full text-[10px] font-bold ring-2", children: reviewer.name.charAt(0).toUpperCase() }), _jsxs("div", { className: "flex flex-col", children: [_jsx("span", { className: "text-xs leading-none font-semibold text-gray-900", children: reviewer.name }), _jsx("span", { className: "text-muted-foreground mt-1 text-[10px] leading-none", children: reviewer.email })] }), _jsx(Button, { variant: "ghost", size: "sm", className: "text-muted-foreground hover:bg-destructive/10 hover:text-destructive h-6 w-6 rounded-full p-0 opacity-50 transition-all hover:opacity-100", onClick: () => removeReviewer(index), children: _jsx(X, { className: "h-3.5 w-3.5" }) })] }, index))) })), _jsxs("div", { className: "flex flex-col gap-4 rounded-xl border border-gray-200 bg-gray-50/50 p-5 shadow-inner", children: [items.length > 0 && (_jsx(PreconfiguredReviewerSelector, { itemIds: itemIds, language: language, onReviewerSelected: (reviewer) => {
|
|
466
|
-
const exists = reviewers.some((r) => r.email.toLowerCase() ===
|
|
467
|
-
reviewer.email.toLowerCase());
|
|
468
|
-
if (!exists) {
|
|
469
|
-
setReviewers([...reviewers, reviewer]);
|
|
470
|
-
}
|
|
471
|
-
}, existingReviewers: reviewers })), _jsxs("div", { className: "flex flex-col gap-2.5", children: [_jsx("label", { className: "text-[11px] font-bold tracking-wider text-gray-500 uppercase", children: "Add new reviewer" }), _jsxs("div", { className: "flex items-start gap-3", children: [_jsx("div", { className: "flex flex-1 flex-col gap-1", children: _jsx(Input, { "data-testid": "reviewer-name-input", placeholder: "Full Name", value: newReviewer.name, onChange: (e) => setNewReviewer({
|
|
472
|
-
...newReviewer,
|
|
473
|
-
name: e.target.value,
|
|
474
|
-
}), onKeyDown: (e) => {
|
|
475
|
-
if (e.key === "Enter") {
|
|
476
|
-
e.preventDefault();
|
|
477
|
-
addReviewer();
|
|
478
|
-
}
|
|
479
|
-
}, className: "bg-white" }) }), _jsxs("div", { className: "flex flex-1 flex-col gap-1", children: [_jsx(Input, { "data-testid": "reviewer-email-input", placeholder: "Email address", value: newReviewer.email, onChange: (e) => setNewReviewer({
|
|
480
|
-
...newReviewer,
|
|
481
|
-
email: e.target.value,
|
|
482
|
-
}), onKeyDown: (e) => {
|
|
483
|
-
if (e.key === "Enter") {
|
|
484
|
-
e.preventDefault();
|
|
485
|
-
addReviewer();
|
|
486
|
-
}
|
|
487
|
-
}, className: `bg-white ${newReviewer.email &&
|
|
488
|
-
!isValidEmail(newReviewer.email)
|
|
489
|
-
? "border-destructive/30 focus:border-destructive"
|
|
490
|
-
: ""}` }), newReviewer.email &&
|
|
491
|
-
!isValidEmail(newReviewer.email) && (_jsx("span", { className: "text-destructive text-[10px] font-medium", children: "Invalid email address" })), newReviewer.email &&
|
|
492
|
-
emailAlreadyExists(newReviewer.email) && (_jsx("span", { className: "text-destructive text-[10px] font-medium", children: "Reviewer already added" }))] }), _jsxs(Button, { onClick: addReviewer, size: "sm", "aria-label": "Add Reviewer", "data-testid": "add-reviewer-button", className: "h-9 shrink-0 px-3", children: [_jsx(Plus, { className: "mr-1.5 h-3.5 w-3.5" }), "Add"] })] })] })] }), showErrors && reviewers.length === 0 && (_jsx("p", { className: "text-destructive text-xs font-medium", children: "Please add at least one reviewer to create this review" }))] }), _jsx("div", { className: "border-t border-gray-100" }), _jsxs("div", { className: "flex flex-col gap-3", children: [_jsx("label", { className: "text-sm font-semibold text-gray-900", children: "Language" }), _jsx("p", { className: "text-muted-foreground text-xs", children: "Choose which language versions to include in the review." }), _jsxs("div", { className: "flex flex-col gap-4", children: [_jsxs("div", { className: "flex flex-wrap gap-6", children: [_jsxs("label", { className: "flex cursor-pointer items-center gap-2", children: [_jsx("input", { type: "radio", name: "languageMode", "data-testid": "language-mode-single", checked: languageMode === "single", onChange: () => {
|
|
493
|
-
setLanguageMode("single");
|
|
494
|
-
setLanguage(selectedLanguages[0] || language);
|
|
495
|
-
}, className: "accent-primary h-4 w-4 cursor-pointer" }), _jsx("span", { className: "text-xs text-gray-700", children: "Single Language" })] }), _jsxs("label", { className: "flex cursor-pointer items-center gap-2", children: [_jsx("input", { type: "radio", name: "languageMode", "data-testid": "language-mode-multiple", checked: languageMode === "multiple", onChange: () => setLanguageMode("multiple"), className: "accent-primary h-4 w-4 cursor-pointer" }), _jsx("span", { className: "text-xs text-gray-700", children: "Multiple Languages" })] }), _jsxs("label", { className: "flex cursor-pointer items-center gap-2", children: [_jsx("input", { type: "radio", name: "languageMode", "data-testid": "language-mode-all", checked: languageMode === "all", onChange: () => setLanguageMode("all"), className: "accent-primary h-4 w-4 cursor-pointer" }), _jsx("span", { className: "text-xs text-gray-700", children: "All Languages" })] })] }), languageMode === "single" && (_jsx("div", { className: "max-w-xs", children: _jsx(LanguageSelector, { selectedLanguage: language, onLanguageSelected: (lang) => {
|
|
496
|
-
setLanguage(lang.languageCode);
|
|
497
|
-
setSelectedLanguages([lang.languageCode]);
|
|
498
|
-
}, showAllLanguages: true }) })), languageMode === "multiple" && (_jsxs("div", { className: "flex max-h-56 flex-col gap-3 overflow-hidden rounded-xl border border-gray-200 bg-white p-4 shadow-sm", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-gray-100 pb-3", children: [_jsx("span", { className: "text-[11px] font-bold tracking-wider text-gray-500 uppercase", children: "Select Languages" }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => {
|
|
499
|
-
const allLangs = editContext?.itemLanguages || [];
|
|
500
|
-
setSelectedLanguages(allLangs.map((l) => l.languageCode));
|
|
501
|
-
}, className: "text-primary hover:bg-primary/5 h-7 px-2 text-xs", children: "Select All" }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => setSelectedLanguages([]), className: "h-7 px-2 text-xs text-gray-500 hover:bg-gray-100", children: "Clear" })] })] }), _jsx("div", { className: "grid grid-cols-2 gap-2 overflow-y-auto pr-2", children: (editContext?.itemLanguages || []).map((lang) => (_jsxs("label", { className: "flex cursor-pointer items-center gap-3 rounded-md p-2 transition-all hover:bg-gray-50", children: [_jsx(Checkbox, { checked: selectedLanguages.includes(lang.languageCode), onCheckedChange: (checked) => {
|
|
502
|
-
if (checked) {
|
|
503
|
-
setSelectedLanguages([
|
|
504
|
-
...selectedLanguages,
|
|
505
|
-
lang.languageCode,
|
|
506
|
-
]);
|
|
507
|
-
}
|
|
508
|
-
else {
|
|
509
|
-
setSelectedLanguages(selectedLanguages.filter((l) => l !== lang.languageCode));
|
|
510
|
-
}
|
|
511
|
-
} }), _jsx("img", { src: lang.icon, className: "h-4 w-4 rounded-sm", alt: lang.name }), _jsx("span", { className: "text-xs font-medium text-gray-700", children: lang.name })] }, lang.languageCode))) }), showErrors && selectedLanguages.length === 0 && (_jsx("p", { className: "text-destructive mt-1 text-center text-xs font-medium", children: "Please select at least one language" }))] })), languageMode === "all" && (_jsx("div", { className: "rounded-lg border border-blue-100 bg-blue-50 p-4 text-sm leading-relaxed font-medium text-blue-700", children: "All available languages will be included in this review. Reviewers will see versions for every language the item exists in." }))] })] }), _jsx("div", { className: "border-t border-gray-100" }), _jsxs("div", { className: "mb-4 flex flex-col", children: [_jsxs("button", { type: "button", "data-testid": "advanced-settings-button", onClick: () => setAdvancedSettingsOpen(!advancedSettingsOpen), className: "flex w-full items-center justify-between rounded-xl border border-gray-200 bg-gray-50/50 px-5 py-4 text-left transition-all hover:bg-gray-100/80 hover:shadow-sm", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "rounded-lg border border-gray-100 bg-white p-2 shadow-sm", children: _jsx(Settings2, { className: "text-primary h-4 w-4" }) }), _jsxs("div", { className: "flex flex-col", children: [_jsx("span", { className: "text-sm leading-tight font-semibold text-gray-900", children: "Advanced Settings" }), _jsx("span", { className: "text-muted-foreground mt-0.5 text-[11px]", children: "Expiration, approvals, security" })] })] }), _jsx(ChevronDown, { className: `h-5 w-5 text-gray-400 transition-transform duration-300 ${advancedSettingsOpen ? "rotate-180" : ""}` })] }), advancedSettingsOpen && (_jsxs("div", { className: "mt-4 flex flex-col gap-6 rounded-xl border border-gray-200 bg-white p-6 shadow-sm", children: [_jsxs("div", { className: "flex flex-col gap-3", children: [_jsx("label", { htmlFor: "requiredApprovals", className: "text-sm font-semibold text-gray-900", children: "Required Approvals" }), _jsx("p", { className: "text-muted-foreground text-xs", children: "Number of reviewers that must approve each page or item before it's considered complete." }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Input, { id: "requiredApprovals", "data-testid": "required-approvals-input", type: "number", min: "1", value: requiredApprovals, onChange: (e) => setRequiredApprovals(e.target.value), placeholder: "1", className: "w-24 bg-gray-50/50" }), _jsx("span", { className: "text-xs font-medium text-gray-400", children: "approvals needed" })] }), showErrors &&
|
|
512
|
-
reviewers.length > 0 &&
|
|
513
|
-
requiredApprovals &&
|
|
514
|
-
(() => {
|
|
515
|
-
const num = parseInt(requiredApprovals, 10);
|
|
516
|
-
if (isNaN(num) || num < 1) {
|
|
517
|
-
return (_jsx("p", { className: "text-destructive text-xs font-medium", children: "Must be at least 1" }));
|
|
518
|
-
}
|
|
519
|
-
if (num > reviewers.length) {
|
|
520
|
-
return (_jsxs("p", { className: "text-destructive text-xs font-medium", children: ["Cannot exceed number of reviewers (", reviewers.length, ")"] }));
|
|
521
|
-
}
|
|
522
|
-
return null;
|
|
523
|
-
})()] })] }), _jsx("div", { className: "border-t border-gray-100" }), _jsxs("div", { className: "flex items-start gap-4", children: [_jsx(Checkbox, { id: "updateWorkflowOnCompletion", "data-testid": "update-workflow-checkbox", checked: updateWorkflowOnCompletion, onCheckedChange: (checked) => setUpdateWorkflowOnCompletion(!!checked), className: "mt-1" }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { htmlFor: "updateWorkflowOnCompletion", className: "cursor-pointer text-sm leading-tight font-semibold text-gray-900", children: "Update workflow state on completion" }), _jsx("span", { className: "text-muted-foreground text-xs leading-relaxed", children: "When the review is approved by all required reviewers, automatically execute the \"Approve\" workflow action." })] })] }), _jsx("div", { className: "border-t border-gray-100" }), _jsxs("div", { className: "flex items-start gap-4", children: [_jsx(Checkbox, { id: "hasExpiration", "data-testid": "set-expiration-checkbox", checked: expirationDays !== "", onCheckedChange: (checked) => {
|
|
524
|
-
if (!checked) {
|
|
525
|
-
setExpirationDays("");
|
|
526
|
-
}
|
|
527
|
-
else {
|
|
528
|
-
setExpirationDays("30");
|
|
529
|
-
}
|
|
530
|
-
}, className: "mt-1" }), _jsxs("div", { className: "flex flex-1 flex-col gap-3", children: [_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { htmlFor: "hasExpiration", className: "cursor-pointer text-sm leading-tight font-semibold text-gray-900", children: "Set expiration" }), _jsx("span", { className: "text-muted-foreground text-xs leading-relaxed", children: "Automatically close the review after a specified number of days if not completed." })] }), expirationDays !== "" && (_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Input, { type: "number", "data-testid": "expiration-days-input", min: "1", value: expirationDays, onChange: (e) => setExpirationDays(e.target.value), placeholder: "30", className: "w-24 bg-gray-50/50" }), _jsx("span", { className: "text-xs font-medium text-gray-400", children: "days remaining" })] }))] })] }), _jsx("div", { className: "border-t border-gray-100" }), _jsxs("div", { className: "flex items-start gap-4", children: [_jsx(Checkbox, { id: "hasSecret", "data-testid": "require-secret-checkbox", checked: showSecretFields, onCheckedChange: (checked) => {
|
|
531
|
-
setShowSecretFields(!!checked);
|
|
532
|
-
if (!checked) {
|
|
533
|
-
setSecret("");
|
|
534
|
-
setSecretConfirm("");
|
|
535
|
-
}
|
|
536
|
-
}, className: "mt-1" }), _jsxs("div", { className: "flex flex-1 flex-col gap-3", children: [_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { htmlFor: "hasSecret", className: "cursor-pointer text-sm leading-tight font-semibold text-gray-900", children: "Require secret to unlock" }), _jsx("span", { className: "text-muted-foreground text-xs leading-relaxed", children: "Reviewers must enter a shared secret phrase before they can access and review the content." })] }), showSecretFields && (_jsxs("div", { className: "grid max-w-md grid-cols-2 gap-3", children: [_jsx(Input, { "data-testid": "secret-input", type: "password", placeholder: "Create secret phrase", value: secret, onChange: (e) => setSecret(e.target.value), autoComplete: "off", className: "bg-gray-50/50" }), _jsx(Input, { "data-testid": "secret-confirm-input", type: "password", placeholder: "Confirm secret phrase", value: secretConfirm, onChange: (e) => setSecretConfirm(e.target.value), autoComplete: "off", className: "bg-gray-50/50" }), showErrors &&
|
|
537
|
-
secret &&
|
|
538
|
-
secret !== secretConfirm && (_jsx("p", { className: "text-destructive col-span-2 text-xs font-medium", children: "Secret phrases do not match" }))] }))] })] })] }))] }), error && (_jsx("div", { className: "border-destructive/20 bg-destructive/10 text-destructive rounded-xl border p-4 text-sm font-medium shadow-sm", children: _jsxs("div", { className: "flex gap-3", children: [_jsx(AlertTriangle, { className: "h-5 w-5 shrink-0" }), _jsx("p", { children: error })] }) }))] }) }), _jsxs(DialogButtons, { hideBorder: true, className: "bg-gray-50/50", children: [_jsx(Button, { variant: "ghost", onClick: () => onOpenChange(false), children: "Cancel" }), _jsx(Button, { "data-testid": "create-review-submit-button", onClick: handleCreate, disabled: loading || !isFormValid, className: "min-w-[140px] shadow-sm", children: loading ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Creating..."] })) : ("Create Review") })] })] })] }) }));
|
|
595
|
+
const handleDialogCancel = () => {
|
|
596
|
+
if (loading)
|
|
597
|
+
return;
|
|
598
|
+
resetDialogState();
|
|
599
|
+
onOpenChange(false);
|
|
600
|
+
};
|
|
601
|
+
const handleDialogOpenChange = (nextOpen) => {
|
|
602
|
+
if (!nextOpen) {
|
|
603
|
+
handleDialogCancel();
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
606
|
+
onOpenChange(nextOpen);
|
|
607
|
+
};
|
|
608
|
+
const handleDone = () => {
|
|
609
|
+
const reviewId = createdReviewId;
|
|
610
|
+
resetDialogState();
|
|
611
|
+
onCreated(reviewId);
|
|
612
|
+
};
|
|
613
|
+
const languageSummary = languageMode === "all"
|
|
614
|
+
? "All languages"
|
|
615
|
+
: languageMode === "multiple"
|
|
616
|
+
? `${selectedLanguages.length} selected (${selectedLanguages.join(", ")})`
|
|
617
|
+
: language;
|
|
618
|
+
return (_jsx(Dialog, { open: open, onOpenChange: handleDialogOpenChange, children: _jsxs(DialogContent, { className: "flex max-w-5xl overflow-hidden border-none p-0 shadow-2xl", style: { height: "90vh", maxHeight: "90vh" }, children: [_jsx(StyledDialogTitle, { icon: step === "success" ? (_jsx(CheckCircle2, { strokeWidth: 1 })) : step === "confirm" ? (_jsx(MailCheck, { strokeWidth: 1 })) : (_jsx(ClipboardCheck, { strokeWidth: 1 })), title: step === "success"
|
|
619
|
+
? "Review Created"
|
|
620
|
+
: step === "confirm"
|
|
621
|
+
? "Confirm Review"
|
|
622
|
+
: "Create Review" }), _jsxs("div", { className: "flex min-h-0 flex-1 flex-col overflow-hidden", children: [_jsxs("div", { className: "flex min-h-0 flex-1 flex-col overflow-y-auto px-6 pb-4", children: [step === "details" && (_jsx(CreateReviewDetailsStep, { items: items, setItems: setItems, showErrors: showErrors, language: language, setLanguage: setLanguage, rootItemIds: rootItemIds, selectedInTree: selectedInTree, setSelectedInTree: setSelectedInTree, selectedFromList: selectedFromList, setSelectedFromList: setSelectedFromList, addToList: addToList, removeFromList: removeFromList, handleAddItem: handleAddItem, removeItem: removeItem, toggleSubitems: toggleSubitems, reviewers: reviewers, setReviewers: setReviewers, newReviewer: newReviewer, setNewReviewer: setNewReviewer, addReviewer: addReviewer, removeReviewer: removeReviewer, isValidEmail: isValidEmail, emailAlreadyExists: emailAlreadyExists, itemIds: itemIds, languageMode: languageMode, setLanguageMode: setLanguageMode, selectedLanguages: selectedLanguages, setSelectedLanguages: setSelectedLanguages, itemLanguages: editContext?.itemLanguages || [], advancedSettingsOpen: advancedSettingsOpen, setAdvancedSettingsOpen: setAdvancedSettingsOpen, requiredApprovals: requiredApprovals, setRequiredApprovals: setRequiredApprovals, updateWorkflowOnCompletion: updateWorkflowOnCompletion, setUpdateWorkflowOnCompletion: setUpdateWorkflowOnCompletion, expirationDays: expirationDays, setExpirationDays: setExpirationDays, showSecretFields: showSecretFields, setShowSecretFields: setShowSecretFields, secret: secret, setSecret: setSecret, secretConfirm: secretConfirm, setSecretConfirm: setSecretConfirm, error: error })), step === "confirm" && (_jsx(CreateReviewConfirmStep, { title: title, setTitle: setTitle, languageSummary: languageSummary, reviewers: reviewers, items: items, requiredApprovals: requiredApprovals, updateWorkflowOnCompletion: updateWorkflowOnCompletion, expirationDays: expirationDays, showSecretFields: showSecretFields, error: error })), step === "success" && (_jsx(CreateReviewSuccessStep, { sentInvitationCount: sentInvitationCount, sentInvitationEmails: sentInvitationEmails }))] }), _jsxs(DialogButtons, { hideBorder: true, className: "bg-gray-50/50", children: [step === "details" && (_jsxs(_Fragment, { children: [_jsx(Button, { variant: "ghost", onClick: handleDialogCancel, children: "Cancel" }), _jsx(Button, { "data-testid": "create-review-submit-button", onClick: handleProceedToConfirm, disabled: loading || isGeneratingTitle || !isFormValid, className: "min-w-[140px] shadow-sm", children: isGeneratingTitle ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Generating Name..."] })) : ("Continue") })] })), step === "confirm" && (_jsxs(_Fragment, { children: [_jsx(Button, { variant: "ghost", onClick: () => {
|
|
623
|
+
setError(null);
|
|
624
|
+
setStep("details");
|
|
625
|
+
}, disabled: loading, children: "Back" }), _jsx(Button, { "data-testid": "create-review-submit-button", onClick: handleCreate, disabled: loading, className: "min-w-[160px] shadow-sm", children: loading ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Creating..."] })) : ("Create & Send Emails") })] })), step === "success" && (_jsx(Button, { onClick: handleDone, className: "min-w-[120px] shadow-sm", children: "Done" }))] })] })] }) }));
|
|
539
626
|
}
|
|
540
627
|
//# sourceMappingURL=CreateReviewDialog.js.map
|