@parhelia/core 0.1.10884 → 0.1.10978
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/components/ui/LanguageSelector.js +10 -4
- package/dist/components/ui/LanguageSelector.js.map +1 -1
- package/dist/config/config.js +19 -28
- package/dist/config/config.js.map +1 -1
- package/dist/config/types.d.ts +0 -5
- package/dist/editor/ContentTree.js +1 -1
- package/dist/editor/ContentTree.js.map +1 -1
- package/dist/editor/FieldListField.js +70 -3
- package/dist/editor/FieldListField.js.map +1 -1
- package/dist/editor/MainLayout.js +77 -8
- package/dist/editor/MainLayout.js.map +1 -1
- package/dist/editor/ai/AgentDocumentList.d.ts +8 -0
- package/dist/editor/ai/AgentDocumentList.js +132 -0
- package/dist/editor/ai/AgentDocumentList.js.map +1 -0
- package/dist/editor/ai/AgentTerminal.js +29 -9
- package/dist/editor/ai/AgentTerminal.js.map +1 -1
- package/dist/editor/ai/ContextInfoBar.d.ts +3 -1
- package/dist/editor/ai/ContextInfoBar.js +3 -3
- package/dist/editor/ai/ContextInfoBar.js.map +1 -1
- package/dist/editor/client/EditorShell.js +34 -8
- package/dist/editor/client/EditorShell.js.map +1 -1
- package/dist/editor/client/editContext.d.ts +3 -0
- package/dist/editor/client/editContext.js.map +1 -1
- package/dist/editor/client/itemsRepository.d.ts +2 -2
- package/dist/editor/client/itemsRepository.js +19 -8
- package/dist/editor/client/itemsRepository.js.map +1 -1
- package/dist/editor/client/pageModelBuilder.js +19 -3
- package/dist/editor/client/pageModelBuilder.js.map +1 -1
- package/dist/editor/control-center/Setup.js +159 -15
- package/dist/editor/control-center/Setup.js.map +1 -1
- package/dist/editor/control-center/setup-steps/AiSetupStep/utils.d.ts +1 -0
- package/dist/editor/control-center/setup-steps/AiSetupStep/utils.js +19 -0
- package/dist/editor/control-center/setup-steps/AiSetupStep/utils.js.map +1 -1
- package/dist/editor/control-center/setup-steps/SetupOverview.d.ts +14 -0
- package/dist/editor/control-center/setup-steps/SetupOverview.js +38 -0
- package/dist/editor/control-center/setup-steps/SetupOverview.js.map +1 -0
- package/dist/editor/editor-warnings/ItemLocked.js +1 -1
- package/dist/editor/editor-warnings/ItemLocked.js.map +1 -1
- package/dist/editor/menubar/toolbar-sections/ReviewCommands.js +13 -13
- package/dist/editor/menubar/toolbar-sections/ReviewCommands.js.map +1 -1
- package/dist/editor/page-viewer/PageViewerFrame.js +0 -11
- package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
- package/dist/editor/page-viewer/pageModelSkeletonBuilder.js +11 -1
- package/dist/editor/page-viewer/pageModelSkeletonBuilder.js.map +1 -1
- package/dist/editor/page-viewer/pageViewContext.js +0 -1
- package/dist/editor/page-viewer/pageViewContext.js.map +1 -1
- package/dist/editor/reviews/CreateReviewDialog.js +308 -30
- package/dist/editor/reviews/CreateReviewDialog.js.map +1 -1
- package/dist/editor/reviews/DecisionsMatrix.d.ts +5 -1
- package/dist/editor/reviews/DecisionsMatrix.js +668 -44
- package/dist/editor/reviews/DecisionsMatrix.js.map +1 -1
- package/dist/editor/reviews/EditReviewSettingsDialog.d.ts +20 -0
- package/dist/editor/reviews/EditReviewSettingsDialog.js +208 -0
- package/dist/editor/reviews/EditReviewSettingsDialog.js.map +1 -0
- package/dist/editor/reviews/ItemTreeSelector.js +5 -3
- package/dist/editor/reviews/ItemTreeSelector.js.map +1 -1
- package/dist/editor/reviews/PagesPanel.d.ts +3 -0
- package/dist/editor/reviews/PagesPanel.js +92 -18
- package/dist/editor/reviews/PagesPanel.js.map +1 -1
- package/dist/editor/reviews/PreconfiguredReviewerSelector.d.ts +9 -0
- package/dist/editor/reviews/PreconfiguredReviewerSelector.js +55 -0
- package/dist/editor/reviews/PreconfiguredReviewerSelector.js.map +1 -0
- package/dist/editor/reviews/ReviewDetail.js +108 -28
- package/dist/editor/reviews/ReviewDetail.js.map +1 -1
- package/dist/editor/reviews/ReviewersPanel.d.ts +3 -1
- package/dist/editor/reviews/ReviewersPanel.js +142 -22
- package/dist/editor/reviews/ReviewersPanel.js.map +1 -1
- package/dist/editor/reviews/ReviewsList.js +65 -7
- package/dist/editor/reviews/ReviewsList.js.map +1 -1
- package/dist/editor/reviews/useMultiReview.d.ts +5 -0
- package/dist/editor/reviews/useMultiReview.js +75 -7
- package/dist/editor/reviews/useMultiReview.js.map +1 -1
- package/dist/editor/services/agentService.d.ts +38 -0
- package/dist/editor/services/agentService.js +84 -0
- package/dist/editor/services/agentService.js.map +1 -1
- package/dist/editor/services/aiService.d.ts +2 -0
- package/dist/editor/services/aiService.js.map +1 -1
- package/dist/editor/services/contentService.d.ts +2 -2
- package/dist/editor/services/contentService.js +12 -4
- package/dist/editor/services/contentService.js.map +1 -1
- package/dist/editor/services/reviewsService.d.ts +8 -1
- package/dist/editor/services/reviewsService.js +32 -4
- package/dist/editor/services/reviewsService.js.map +1 -1
- package/dist/editor/services/suggestedEditsService.d.ts +1 -1
- package/dist/editor/services/suggestedEditsService.js +10 -2
- package/dist/editor/services/suggestedEditsService.js.map +1 -1
- package/dist/editor/sidebar/ComponentTree.js +43 -32
- package/dist/editor/sidebar/ComponentTree.js.map +1 -1
- package/dist/editor/sidebar/Sidebar.js +1 -1
- package/dist/editor/sidebar/Sidebar.js.map +1 -1
- package/dist/editor/sidebar/SidebarView.d.ts +4 -1
- package/dist/editor/sidebar/SidebarView.js +23 -10
- package/dist/editor/sidebar/SidebarView.js.map +1 -1
- package/dist/editor/ui/IconSelectorDialog.js +8 -4
- package/dist/editor/ui/IconSelectorDialog.js.map +1 -1
- package/dist/editor/ui/ItemNameDialogNew.js +14 -0
- package/dist/editor/ui/ItemNameDialogNew.js.map +1 -1
- package/dist/editor/utils.js +21 -4
- package/dist/editor/utils.js.map +1 -1
- package/dist/editor/views/SingleEditView.js +1 -1
- package/dist/editor/views/SingleEditView.js.map +1 -1
- package/dist/setup/services/setupWizardService.d.ts +7 -2
- package/dist/setup/services/setupWizardService.js +7 -14
- package/dist/setup/services/setupWizardService.js.map +1 -1
- package/dist/setup/utils/modelPricing.d.ts +7 -0
- package/dist/setup/utils/modelPricing.js +106 -0
- package/dist/setup/utils/modelPricing.js.map +1 -0
- package/dist/setup/wizard/steps/AgentsStep.js +6 -15
- package/dist/setup/wizard/steps/AgentsStep.js.map +1 -1
- package/dist/setup/wizard/steps/ModelsStep.js +182 -79
- package/dist/setup/wizard/steps/ModelsStep.js.map +1 -1
- package/dist/splash-screen/NewPage.js +1 -1
- package/dist/splash-screen/NewPage.js.map +1 -1
- package/dist/styles.css +33 -14
- package/dist/types.d.ts +17 -5
- package/package.json +2 -2
- package/dist/editor/control-center/parhelia-setup/Overview.d.ts +0 -1
- package/dist/editor/control-center/parhelia-setup/Overview.js +0 -91
- package/dist/editor/control-center/parhelia-setup/Overview.js.map +0 -1
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ReviewerInfo } from "../../types";
|
|
2
|
+
type PreconfiguredReviewerSelectorProps = {
|
|
3
|
+
itemIds: string[];
|
|
4
|
+
language: string;
|
|
5
|
+
onReviewerSelected: (reviewer: ReviewerInfo) => void;
|
|
6
|
+
existingReviewers: ReviewerInfo[];
|
|
7
|
+
};
|
|
8
|
+
export declare function PreconfiguredReviewerSelector({ itemIds, language, onReviewerSelected, existingReviewers, }: PreconfiguredReviewerSelectorProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect } from "react";
|
|
3
|
+
import { Select } from "../../components/ui/select";
|
|
4
|
+
import { getPreconfiguredReviewers } from "../services/reviewsService";
|
|
5
|
+
import { Loader2 } from "lucide-react";
|
|
6
|
+
export function PreconfiguredReviewerSelector({ itemIds, language, onReviewerSelected, existingReviewers, }) {
|
|
7
|
+
const [preconfiguredReviewers, setPreconfiguredReviewers] = useState([]);
|
|
8
|
+
const [loading, setLoading] = useState(false);
|
|
9
|
+
const [selectedValue, setSelectedValue] = useState("");
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
if (itemIds.length === 0) {
|
|
12
|
+
setPreconfiguredReviewers([]);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const fetchReviewers = async () => {
|
|
16
|
+
setLoading(true);
|
|
17
|
+
try {
|
|
18
|
+
const result = await getPreconfiguredReviewers(itemIds, language);
|
|
19
|
+
if (result.data) {
|
|
20
|
+
setPreconfiguredReviewers(result.data);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
console.error("Failed to fetch preconfigured reviewers:", error);
|
|
25
|
+
setPreconfiguredReviewers([]);
|
|
26
|
+
}
|
|
27
|
+
finally {
|
|
28
|
+
setLoading(false);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
fetchReviewers();
|
|
32
|
+
}, [itemIds, language]);
|
|
33
|
+
// Filter out reviewers that are already added (by email, case-insensitive)
|
|
34
|
+
const availableReviewers = preconfiguredReviewers.filter((reviewer) => {
|
|
35
|
+
return !existingReviewers.some((existing) => existing.email.toLowerCase() === reviewer.email.toLowerCase());
|
|
36
|
+
});
|
|
37
|
+
// Create options for the select dropdown
|
|
38
|
+
const options = availableReviewers.map((reviewer) => ({
|
|
39
|
+
value: reviewer.email,
|
|
40
|
+
label: `${reviewer.name} (${reviewer.email})`,
|
|
41
|
+
}));
|
|
42
|
+
const handleSelection = (value) => {
|
|
43
|
+
if (!value)
|
|
44
|
+
return;
|
|
45
|
+
const selectedReviewer = availableReviewers.find((r) => r.email === value);
|
|
46
|
+
if (selectedReviewer) {
|
|
47
|
+
onReviewerSelected(selectedReviewer);
|
|
48
|
+
setSelectedValue(""); // Reset selection after adding
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
return (_jsxs("div", { className: "my-2 flex flex-col gap-1", children: [_jsx("label", { className: "text-xs font-medium text-gray-700", children: "Predefined Reviewers" }), loading ? (_jsxs("div", { className: "flex items-center gap-2 text-xs text-gray-500", children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin" }), _jsx("span", { children: "Loading reviewers..." })] })) : availableReviewers.length === 0 ? (_jsx("div", { className: "text-xs text-gray-500", children: preconfiguredReviewers.length === 0
|
|
52
|
+
? "No predefined reviewers configured for these items"
|
|
53
|
+
: "All predefined reviewers have been added" })) : (_jsx(Select, { value: selectedValue, onValueChange: handleSelection, options: options, placeholder: "Select a reviewer...", disabled: options.length === 0, emptyMessage: "No reviewers available" }))] }));
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=PreconfiguredReviewerSelector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PreconfiguredReviewerSelector.js","sourceRoot":"","sources":["../../../src/editor/reviews/PreconfiguredReviewerSelector.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,29 +1,104 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useState } from "react";
|
|
2
|
+
import { useEffect, useState, useRef } from "react";
|
|
3
3
|
import { ReviewersPanel } from "./ReviewersPanel";
|
|
4
4
|
import { DecisionsMatrix } from "./DecisionsMatrix";
|
|
5
5
|
import { SimpleToolbar } from "../ui/SimpleToolbar";
|
|
6
6
|
import { SimpleIconButton } from "../ui/SimpleIconButton";
|
|
7
7
|
import { Splitter } from "../ui/Splitter";
|
|
8
|
-
import { ArrowLeft, Loader2,
|
|
8
|
+
import { ArrowLeft, Loader2, Lock, Settings } from "lucide-react";
|
|
9
9
|
import { formatDate } from "../utils";
|
|
10
10
|
import { Badge } from "../../components/ui/badge";
|
|
11
|
-
import { Check } from "lucide-react";
|
|
12
11
|
import { useEditContext } from "../client/editContext";
|
|
13
12
|
import { Button } from "../../components/ui/button";
|
|
14
13
|
import { Input } from "../../components/ui/input";
|
|
15
14
|
import { unlockReview } from "../services/reviewsService";
|
|
15
|
+
import { EditReviewSettingsDialog } from "./EditReviewSettingsDialog";
|
|
16
|
+
import { loadAiProfiles } from "../services/aiService";
|
|
16
17
|
export function ReviewDetail({ reviewId, onBack, multiReview, }) {
|
|
17
18
|
const editContext = useEditContext();
|
|
18
19
|
const [selectedReviewerId, setSelectedReviewerId] = useState(null);
|
|
19
20
|
const [secret, setSecret] = useState("");
|
|
20
21
|
const [unlocking, setUnlocking] = useState(false);
|
|
21
22
|
const [unlockError, setUnlockError] = useState(null);
|
|
23
|
+
const [editSettingsOpen, setEditSettingsOpen] = useState(false);
|
|
24
|
+
const agentLaunchedRef = useRef(false);
|
|
22
25
|
useEffect(() => {
|
|
23
26
|
if (reviewId && !multiReview.reviewDetail) {
|
|
24
27
|
multiReview.setSelectedReviewId(reviewId);
|
|
25
28
|
}
|
|
29
|
+
// Reset agent launch flag when review changes
|
|
30
|
+
agentLaunchedRef.current = false;
|
|
26
31
|
}, [reviewId, multiReview]);
|
|
32
|
+
// Auto-launch agent when review is opened/unlocked
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
const launchAgentForReview = async () => {
|
|
35
|
+
// Only launch once per review
|
|
36
|
+
if (agentLaunchedRef.current || !multiReview.reviewDetail) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const { review, items } = multiReview.reviewDetail;
|
|
40
|
+
const requiresSecret = multiReview.reviewDetail.requiresSecret ??
|
|
41
|
+
review.requiresSecret ??
|
|
42
|
+
false;
|
|
43
|
+
const secretValidated = multiReview.reviewDetail.secretValidated ?? false;
|
|
44
|
+
// Only launch if review is accessible (no secret required, or secret validated, and items are loaded)
|
|
45
|
+
if (items.length === 0) {
|
|
46
|
+
return; // Items not loaded yet
|
|
47
|
+
}
|
|
48
|
+
if (requiresSecret && !secretValidated) {
|
|
49
|
+
return; // Still needs unlock
|
|
50
|
+
}
|
|
51
|
+
// Check if user is a preview user (review link context)
|
|
52
|
+
const isPreviewUser = editContext?.user?.isLimitedPreviewUser ?? false;
|
|
53
|
+
if (!isPreviewUser) {
|
|
54
|
+
return; // Only auto-launch for preview users accessing via review link
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
// Load available profiles (will be filtered by backend policy)
|
|
58
|
+
const profiles = await loadAiProfiles();
|
|
59
|
+
if (!profiles || profiles.length === 0) {
|
|
60
|
+
return; // No profiles available
|
|
61
|
+
}
|
|
62
|
+
// Use first available profile
|
|
63
|
+
const firstProfile = profiles[0];
|
|
64
|
+
if (!firstProfile) {
|
|
65
|
+
return; // No profile available
|
|
66
|
+
}
|
|
67
|
+
// Open agents panel
|
|
68
|
+
editContext?.setShowAgentsPanel?.(true);
|
|
69
|
+
// Create agent metadata with review context
|
|
70
|
+
const metadata = {
|
|
71
|
+
items: items.map((item) => ({
|
|
72
|
+
id: item.itemId,
|
|
73
|
+
language: item.language,
|
|
74
|
+
version: 0, // Review items don't have version, default to 0
|
|
75
|
+
name: item.name,
|
|
76
|
+
})),
|
|
77
|
+
additionalData: {
|
|
78
|
+
profileId: firstProfile.id,
|
|
79
|
+
profileName: firstProfile.name,
|
|
80
|
+
initialPrompt: `This agent is assisting with review: ${review.title || review.reviewId.slice(0, 8)}`,
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
// Dispatch event to create agent
|
|
84
|
+
setTimeout(() => {
|
|
85
|
+
try {
|
|
86
|
+
window.dispatchEvent(new CustomEvent("editor:addNewAgent", {
|
|
87
|
+
detail: { metadata },
|
|
88
|
+
}));
|
|
89
|
+
agentLaunchedRef.current = true;
|
|
90
|
+
}
|
|
91
|
+
catch (e) {
|
|
92
|
+
console.error("Failed to launch agent for review:", e);
|
|
93
|
+
}
|
|
94
|
+
}, 100);
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
console.error("Failed to launch agent for review:", error);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
launchAgentForReview();
|
|
101
|
+
}, [multiReview.reviewDetail, editContext]);
|
|
27
102
|
if (multiReview.loading && !multiReview.reviewDetail) {
|
|
28
103
|
return (_jsx("div", { className: "flex h-full items-center justify-center", children: _jsx(Loader2, { className: "h-8 w-8 animate-spin" }) }));
|
|
29
104
|
}
|
|
@@ -34,6 +109,8 @@ export function ReviewDetail({ reviewId, onBack, multiReview, }) {
|
|
|
34
109
|
return (_jsxs("div", { className: "flex h-full flex-col", children: [_jsx(SimpleToolbar, { children: _jsx(SimpleIconButton, { label: "Back", icon: _jsx(ArrowLeft, { className: "h-4 w-4" }), onClick: onBack }) }), _jsx("div", { className: "flex flex-1 items-center justify-center", children: _jsx("div", { className: "text-gray-500", children: "Review not found" }) })] }));
|
|
35
110
|
}
|
|
36
111
|
const { review, assignments, items } = multiReview.reviewDetail;
|
|
112
|
+
// Extract item IDs for predefined reviewer selector
|
|
113
|
+
const itemIds = items.map((item) => item.itemId);
|
|
37
114
|
// Check if unlock is needed (from the status response, not just review object)
|
|
38
115
|
const requiresSecret = multiReview.reviewDetail.requiresSecret ?? review.requiresSecret ?? false;
|
|
39
116
|
const secretValidated = multiReview.reviewDetail.secretValidated ?? false;
|
|
@@ -52,6 +129,8 @@ export function ReviewDetail({ reviewId, onBack, multiReview, }) {
|
|
|
52
129
|
// Refresh the review detail to get the items
|
|
53
130
|
await multiReview.refreshReviewDetail?.();
|
|
54
131
|
setSecret("");
|
|
132
|
+
// Reset agent launch flag so agent can be launched after unlock
|
|
133
|
+
agentLaunchedRef.current = false;
|
|
55
134
|
}
|
|
56
135
|
else if (result.data?.expired) {
|
|
57
136
|
setUnlockError("This review has expired");
|
|
@@ -69,41 +148,42 @@ export function ReviewDetail({ reviewId, onBack, multiReview, }) {
|
|
|
69
148
|
};
|
|
70
149
|
// Show unlock panel if secret is required and not validated
|
|
71
150
|
if (needsUnlock || (requiresSecret && !secretValidated)) {
|
|
72
|
-
return (_jsxs("div", { className: "flex h-full flex-col", children: [_jsx(SimpleToolbar, { children: _jsx(SimpleIconButton, { label: "Back", icon: _jsx(ArrowLeft, { className: "h-4 w-4" }), onClick: onBack }) }), _jsx("div", { className: "flex flex-1 items-center justify-center", children: _jsxs("div", { className: "flex flex-col items-center gap-4
|
|
151
|
+
return (_jsxs("div", { className: "flex h-full flex-col", children: [_jsx(SimpleToolbar, { children: _jsx(SimpleIconButton, { label: "Back", icon: _jsx(ArrowLeft, { className: "h-4 w-4" }), onClick: onBack }) }), _jsx("div", { className: "flex flex-1 items-center justify-center", children: _jsxs("div", { className: "flex w-full max-w-md flex-col items-center gap-4 p-8", children: [_jsx(Lock, { className: "h-12 w-12 text-gray-400" }), _jsx("h2", { className: "text-xl font-semibold", children: review.title || `Review ${review.reviewId.slice(0, 8)}` }), _jsx("p", { className: "text-center text-sm text-gray-600", children: "This review requires a secret to access. Please enter the secret provided by the review creator." }), isExpired && (_jsx("div", { className: "rounded bg-red-100 p-3 text-sm text-red-700", children: "This review has expired and is no longer accessible." })), !isExpired && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex w-full flex-col gap-2", children: [_jsx(Input, { type: "password", placeholder: "Enter secret", value: secret, onChange: (e) => {
|
|
73
152
|
setSecret(e.target.value);
|
|
74
153
|
setUnlockError(null);
|
|
75
154
|
}, onKeyDown: (e) => {
|
|
76
155
|
if (e.key === "Enter") {
|
|
77
156
|
handleUnlock();
|
|
78
157
|
}
|
|
79
|
-
}, disabled: unlocking }), unlockError && (_jsx("div", { className: "text-sm text-red-600", children: unlockError }))] }), _jsx(Button, { onClick: handleUnlock, disabled: unlocking || !secret.trim(), className: "w-full", children: unlocking ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Unlocking..."] })) : ("Unlock Review") })] }))] }) })] }));
|
|
158
|
+
}, disabled: unlocking, autoComplete: "off" }), unlockError && (_jsx("div", { className: "text-sm text-red-600", children: unlockError }))] }), _jsx(Button, { onClick: handleUnlock, disabled: unlocking || !secret.trim(), className: "w-full", children: unlocking ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Unlocking..."] })) : ("Unlock Review") })] }))] }) })] }));
|
|
80
159
|
}
|
|
81
|
-
const getFinalDecisionBadge = () => {
|
|
82
|
-
if (review.finalDecision === "Approved") {
|
|
83
|
-
return (_jsxs(Badge, { variant: "default", className: "bg-green-500", children: [_jsx(Check, { className: "mr-1 h-3 w-3" }), "Approved", review.finalDecisionDate &&
|
|
84
|
-
` - ${formatDate(new Date(review.finalDecisionDate))}`] }));
|
|
85
|
-
}
|
|
86
|
-
if (review.finalDecision === "Rejected") {
|
|
87
|
-
return (_jsxs(Badge, { variant: "destructive", children: [_jsx(X, { className: "mr-1 h-3 w-3" }), "Rejected", review.finalDecisionDate &&
|
|
88
|
-
` - ${formatDate(new Date(review.finalDecisionDate))}`] }));
|
|
89
|
-
}
|
|
90
|
-
return null;
|
|
91
|
-
};
|
|
92
160
|
const allReviewersResponded = assignments.every((assignment) => {
|
|
93
161
|
const decisionsCount = assignment.decisions?.length || 0;
|
|
94
162
|
return decisionsCount === items.length;
|
|
95
163
|
});
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
164
|
+
// Check if current user is the review creator
|
|
165
|
+
const isCreator = review.createdBy === editContext?.user?.name;
|
|
166
|
+
const isLimitedPreviewUser = editContext?.user?.isLimitedPreviewUser ?? false;
|
|
167
|
+
// Build panels array - exclude reviewers panel for limited preview users
|
|
168
|
+
const panels = [
|
|
169
|
+
...(isLimitedPreviewUser
|
|
170
|
+
? []
|
|
171
|
+
: [
|
|
172
|
+
{
|
|
173
|
+
name: "reviewers",
|
|
174
|
+
defaultSize: 200,
|
|
175
|
+
content: (_jsx(ReviewersPanel, { assignments: assignments, onAddReviewer: (reviewers) => multiReview.addReviewersToReview(reviewId, reviewers), onRemoveReviewer: (assignmentId) => multiReview.removeReviewerFromReview(assignmentId), onSendInvitations: (assignmentIds) => multiReview.sendReviewInvitations(assignmentIds), loading: multiReview.loading, selectedReviewerId: selectedReviewerId, onSelectReviewer: setSelectedReviewerId, itemIds: itemIds, language: review.language })),
|
|
176
|
+
},
|
|
177
|
+
]),
|
|
178
|
+
{
|
|
179
|
+
name: "decisions",
|
|
180
|
+
defaultSize: "auto",
|
|
181
|
+
content: (_jsx(DecisionsMatrix, { items: items, assignments: assignments, onMakeDecision: multiReview.makeItemDecision, loading: multiReview.loading, reviewId: reviewId, language: review.language, finalDecision: review.finalDecision, onSetFinalDecision: (decision) => multiReview.setReviewFinalDecision(reviewId, decision), onAddPages: (items) => multiReview.addPages(reviewId, items), onRemovePages: (items) => multiReview.removePages(reviewId, items), allReviewersResponded: allReviewersResponded, selectedReviewerId: selectedReviewerId, currentUserEmail: editContext?.user?.email, requiredApprovals: review.requiredApprovals })),
|
|
182
|
+
},
|
|
183
|
+
];
|
|
184
|
+
return (_jsxs("div", { className: "flex h-full flex-col", children: [_jsx(SimpleToolbar, { children: _jsx(SimpleIconButton, { label: "Back", icon: _jsx(ArrowLeft, { className: "h-4 w-4" }), onClick: onBack }) }), _jsx("div", { className: "border-b p-4", children: _jsxs("div", { className: "flex items-start justify-between", children: [_jsxs("div", { className: "flex-1", children: [_jsx("h2", { className: "text-lg font-semibold", children: review.title || `Review ${review.reviewId.slice(0, 8)}` }), _jsxs("div", { className: "mt-2 flex items-center gap-4 text-xs text-gray-500", children: [_jsxs("span", { children: ["Created: ", formatDate(new Date(review.createdAt))] }), _jsxs("span", { children: ["By: ", review.createdBy] }), _jsxs("span", { className: "flex items-center gap-1", children: ["Language:", " ", review.language === "*" ? (_jsx(Badge, { variant: "outline", children: "All Languages" })) : review.language === "mixed" ? (_jsx("span", { children: "Multiple Languages" })) : (review.language.toUpperCase())] })] })] }), isCreator && (_jsx(SimpleIconButton, { label: "Edit Settings", icon: _jsx(Settings, { className: "h-4 w-4" }), onClick: () => setEditSettingsOpen(true) }))] }) }), _jsx(Splitter, { direction: "vertical", localStorageKey: `review-detail-splitter-${reviewId}`, panels: panels }), _jsx(EditReviewSettingsDialog, { open: editSettingsOpen, onOpenChange: setEditSettingsOpen, review: review, items: items, reviewersCount: assignments.length, onUpdated: async () => {
|
|
185
|
+
// Refresh review detail after settings update
|
|
186
|
+
await multiReview.refreshReviewDetail?.();
|
|
187
|
+
} })] }));
|
|
108
188
|
}
|
|
109
189
|
//# sourceMappingURL=ReviewDetail.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReviewDetail.js","sourceRoot":"","sources":["../../../src/editor/reviews/ReviewDetail.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"ReviewDetail.js","sourceRoot":"","sources":["../../../src/editor/reviews/ReviewDetail.tsx"],"names":[],"mappings":"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"}
|
|
@@ -7,6 +7,8 @@ type ReviewersPanelProps = {
|
|
|
7
7
|
loading: boolean;
|
|
8
8
|
selectedReviewerId?: string | null;
|
|
9
9
|
onSelectReviewer: (assignmentId: string | null) => void;
|
|
10
|
+
itemIds?: string[];
|
|
11
|
+
language?: string;
|
|
10
12
|
};
|
|
11
|
-
export declare function ReviewersPanel({ assignments, onAddReviewer, onRemoveReviewer, onSendInvitations, loading, selectedReviewerId, onSelectReviewer, }: ReviewersPanelProps): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export declare function ReviewersPanel({ assignments, onAddReviewer, onRemoveReviewer, onSendInvitations, loading, selectedReviewerId, onSelectReviewer, itemIds, language, }: ReviewersPanelProps): import("react/jsx-runtime").JSX.Element;
|
|
12
14
|
export {};
|
|
@@ -10,7 +10,16 @@ import { Popover, PopoverContent, PopoverTrigger, } from "../../components/ui/po
|
|
|
10
10
|
import { Input } from "../../components/ui/input";
|
|
11
11
|
import { Loader2 } from "lucide-react";
|
|
12
12
|
import { cn } from "../../lib/utils";
|
|
13
|
-
|
|
13
|
+
import { PreconfiguredReviewerSelector } from "./PreconfiguredReviewerSelector";
|
|
14
|
+
import { useEditContext } from "../client/editContext";
|
|
15
|
+
export function ReviewersPanel({ assignments, onAddReviewer, onRemoveReviewer, onSendInvitations, loading, selectedReviewerId, onSelectReviewer, itemIds = [], language, }) {
|
|
16
|
+
const editContext = useEditContext();
|
|
17
|
+
const isLimitedPreviewUser = editContext?.user?.isLimitedPreviewUser ?? false;
|
|
18
|
+
const currentUserEmail = editContext?.user?.email;
|
|
19
|
+
// For limited preview users, only show their own assignment
|
|
20
|
+
const displayAssignments = isLimitedPreviewUser && currentUserEmail
|
|
21
|
+
? assignments.filter((a) => a.reviewerEmail.toLowerCase() === currentUserEmail.toLowerCase())
|
|
22
|
+
: assignments;
|
|
14
23
|
const [isAddReviewerOpen, setIsAddReviewerOpen] = useState(false);
|
|
15
24
|
const [selectedAssignments, setSelectedAssignments] = useState(new Set());
|
|
16
25
|
const [newReviewer, setNewReviewer] = useState({
|
|
@@ -19,6 +28,8 @@ export function ReviewersPanel({ assignments, onAddReviewer, onRemoveReviewer, o
|
|
|
19
28
|
});
|
|
20
29
|
const [showErrors, setShowErrors] = useState(false);
|
|
21
30
|
const [waiting, setWaiting] = useState(false);
|
|
31
|
+
const [invitationErrors, setInvitationErrors] = useState(new Map());
|
|
32
|
+
const [sendingInvitations, setSendingInvitations] = useState(new Set());
|
|
22
33
|
const isValidEmail = (email) => {
|
|
23
34
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
24
35
|
return emailRegex.test(email);
|
|
@@ -48,38 +59,95 @@ export function ReviewersPanel({ assignments, onAddReviewer, onRemoveReviewer, o
|
|
|
48
59
|
if (selectedAssignments.size === 0)
|
|
49
60
|
return;
|
|
50
61
|
const assignmentIds = Array.from(selectedAssignments);
|
|
51
|
-
|
|
52
|
-
|
|
62
|
+
setSendingInvitations(new Set(assignmentIds));
|
|
63
|
+
setInvitationErrors(new Map());
|
|
64
|
+
try {
|
|
65
|
+
await onSendInvitations(assignmentIds);
|
|
66
|
+
setSelectedAssignments(new Set());
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
const errorMap = new Map();
|
|
70
|
+
// Check if there are individual assignment errors
|
|
71
|
+
if (err && typeof err === "object" && "assignmentErrors" in err) {
|
|
72
|
+
const assignmentErrorMap = err.assignmentErrors;
|
|
73
|
+
if (assignmentErrorMap) {
|
|
74
|
+
// Use individual errors for each assignment
|
|
75
|
+
assignmentIds.forEach((id) => {
|
|
76
|
+
if (assignmentErrorMap.has(id)) {
|
|
77
|
+
let errorMsg = assignmentErrorMap.get(id);
|
|
78
|
+
// Ensure error message is a string, not JSON
|
|
79
|
+
if (typeof errorMsg !== "string") {
|
|
80
|
+
errorMsg = String(errorMsg);
|
|
81
|
+
}
|
|
82
|
+
errorMap.set(id, errorMsg);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// If no individual errors, use the general error message for all
|
|
88
|
+
if (errorMap.size === 0) {
|
|
89
|
+
let errorMessage = err instanceof Error ? err.message : "Failed to send invitations";
|
|
90
|
+
// Ensure error message is a string, not JSON
|
|
91
|
+
if (typeof errorMessage !== "string") {
|
|
92
|
+
errorMessage = String(errorMessage);
|
|
93
|
+
}
|
|
94
|
+
assignmentIds.forEach((id) => {
|
|
95
|
+
errorMap.set(id, errorMessage);
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
setInvitationErrors(errorMap);
|
|
99
|
+
}
|
|
100
|
+
finally {
|
|
101
|
+
setSendingInvitations(new Set());
|
|
102
|
+
}
|
|
53
103
|
};
|
|
54
104
|
const getReviewerStatus = (assignment) => {
|
|
55
|
-
|
|
105
|
+
// Count unique items that have decisions (by itemId + itemLanguage)
|
|
106
|
+
const uniqueItemsWithDecisions = new Set(assignment.decisions?.map((d) => `${d.itemId}:${d.itemLanguage}`) || []);
|
|
107
|
+
const decisionsCount = uniqueItemsWithDecisions.size;
|
|
108
|
+
const totalDecisions = itemIds?.length || 0;
|
|
56
109
|
if (decisionsCount > 0) {
|
|
57
|
-
return (_jsxs("div", { className: "flex items-center gap-1 text-xs text-green-600", children: [_jsx(Check, { className: "h-3 w-3" }), "Responded (", decisionsCount, " decisions)"] }));
|
|
110
|
+
return (_jsxs("div", { className: "flex items-center gap-1 text-xs text-green-600", children: [_jsx(Check, { className: "h-3 w-3" }), "Responded (", decisionsCount, "/", totalDecisions, " decisions)"] }));
|
|
58
111
|
}
|
|
59
112
|
if (assignment.invitationSentDate) {
|
|
60
113
|
return (_jsxs("div", { className: "flex items-center gap-1 text-xs text-blue-600", children: [_jsx(Mail, { className: "h-3 w-3" }), "Invited ", formatDate(new Date(assignment.invitationSentDate))] }));
|
|
61
114
|
}
|
|
62
115
|
return (_jsxs("div", { className: "flex items-center gap-1 text-xs text-gray-500", children: [_jsx(Clock, { className: "h-3 w-3" }), "Not invited"] }));
|
|
63
116
|
};
|
|
64
|
-
const canSendInvitations =
|
|
65
|
-
return (_jsxs("div", { className: "flex h-full flex-col", children: [_jsxs(SimpleToolbar, { children: [_jsxs(Popover, { open: isAddReviewerOpen, onOpenChange: setIsAddReviewerOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(SimpleIconButton, { label: "Add Reviewer", icon: _jsx(Plus, { className: "h-4 w-4" }), "data-testid": "add-reviewer-button", onClick: () => {
|
|
117
|
+
const canSendInvitations = displayAssignments.some((a) => !a.invitationSentDate && selectedAssignments.has(a.assignmentId));
|
|
118
|
+
return (_jsxs("div", { className: "flex h-full flex-col", children: [_jsxs(SimpleToolbar, { children: [!isLimitedPreviewUser && (_jsxs(Popover, { open: isAddReviewerOpen, onOpenChange: setIsAddReviewerOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(SimpleIconButton, { label: "Add Reviewer", icon: _jsx(Plus, { className: "h-4 w-4" }), "data-testid": "add-reviewer-button", onClick: () => {
|
|
66
119
|
setIsAddReviewerOpen(true);
|
|
67
120
|
setTimeout(() => {
|
|
68
121
|
document.getElementById("reviewer-name")?.focus();
|
|
69
122
|
}, 100);
|
|
70
|
-
} }) }), _jsx(PopoverContent, { className: "m-2", children:
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
123
|
+
} }) }), _jsx(PopoverContent, { className: "m-2", children: _jsxs("div", { className: "flex flex-col gap-2 p-2 text-xs", "data-testid": "add-reviewer-popover", children: [itemIds.length > 0 && language ? (_jsx(PreconfiguredReviewerSelector, { itemIds: itemIds, language: language, onReviewerSelected: async (reviewer) => {
|
|
124
|
+
// Check if reviewer already exists (by email, case-insensitive)
|
|
125
|
+
const exists = assignments.some((a) => a.reviewerEmail.toLowerCase() ===
|
|
126
|
+
reviewer.email.toLowerCase());
|
|
127
|
+
if (!exists) {
|
|
128
|
+
await onAddReviewer([reviewer]);
|
|
129
|
+
setIsAddReviewerOpen(false);
|
|
130
|
+
}
|
|
131
|
+
}, existingReviewers: assignments.map((a) => ({
|
|
132
|
+
name: a.reviewerName,
|
|
133
|
+
email: a.reviewerEmail,
|
|
134
|
+
})) })) : (_jsx("div", { className: "mb-2 text-xs text-gray-500", children: !language
|
|
135
|
+
? "Language not available"
|
|
136
|
+
: itemIds.length === 0
|
|
137
|
+
? "No items in review"
|
|
138
|
+
: "Predefined reviewers not available" })), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx("label", { className: "text-xs font-medium text-gray-700", children: "New Reviewer" }), _jsx("label", { htmlFor: "reviewer-name", children: "Name" }), _jsx(Input, { id: "reviewer-name", className: "w-full", value: newReviewer?.name, onChange: (e) => {
|
|
139
|
+
setNewReviewer((x) => ({
|
|
140
|
+
...x,
|
|
141
|
+
name: e.target.value,
|
|
142
|
+
}));
|
|
143
|
+
}, autoFocus: true }), showErrors && !newReviewer?.name && (_jsx("small", { className: "text-red-500", children: "Name is required" })), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx("label", { htmlFor: "reviewer-email", children: "Email" }), _jsx(Input, { id: "reviewer-email", className: "w-full", value: newReviewer?.email, onChange: (e) => {
|
|
144
|
+
setNewReviewer((x) => ({
|
|
145
|
+
...x,
|
|
146
|
+
email: e.target.value,
|
|
147
|
+
}));
|
|
148
|
+
} }), showErrors && !isValidEmail(newReviewer.email) && (_jsx("small", { className: "text-red-500", children: "Not a valid email address" })), showErrors && emailAlreadyExists(newReviewer.email) && (_jsx("small", { className: "text-red-500", children: "Email already exists" }))] }), _jsx(Button, { disabled: waiting, "data-testid": "add-reviewer-submit-button", onClick: handleAddReviewer, children: waiting ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Adding..."] })) : (_jsxs(_Fragment, { children: [_jsx(Plus, { className: "mr-2 h-4 w-4" }), "Add Reviewer"] })) })] })] }) })] })), !isLimitedPreviewUser && canSendInvitations && (_jsx(SimpleIconButton, { label: "Send Invitations", icon: _jsx(Send, { className: "h-4 w-4" }), onClick: handleSendInvitations, disabled: loading }))] }), _jsx("div", { className: "flex-1 overflow-y-auto p-2", children: displayAssignments.length === 0 ? (_jsx("div", { className: "flex h-full items-center justify-center text-sm text-gray-500", children: "No reviewers assigned" })) : (_jsxs("div", { className: "space-y-2", children: [!isLimitedPreviewUser && (_jsx(Button, { variant: "outline", size: "sm", className: cn("w-full justify-start", !selectedReviewerId && "border-blue-500 bg-blue-50"), onClick: () => onSelectReviewer(null), children: "All Reviewers" })), displayAssignments.map((assignment) => (_jsx("div", { className: cn("cursor-pointer rounded border p-3 transition-colors", selectedReviewerId === assignment.assignmentId
|
|
81
149
|
? "border-blue-500 bg-blue-50"
|
|
82
|
-
: "hover:bg-gray-50"), onClick: () => onSelectReviewer(assignment.assignmentId), children: _jsxs("div", { className: "flex items-start justify-between", children: [_jsxs("div", { className: "flex-1", children: [_jsx("div", { className: "font-medium", children: assignment.reviewerName }), _jsx("div", { className: "text-xs text-gray-500", children: assignment.reviewerEmail }), getReviewerStatus(assignment), assignment.assignedBy && (_jsxs("div", { className: "mt-1 text-xs text-gray-400", children: ["Assigned by ", assignment.assignedBy] }))] }), _jsxs("div", { className: "flex items-center gap-2", onClick: (e) => e.stopPropagation(), children: [!assignment.invitationSentDate && (_jsx(Checkbox, { checked: selectedAssignments.has(assignment.assignmentId), onCheckedChange: (checked) => {
|
|
150
|
+
: "hover:bg-gray-50"), onClick: () => onSelectReviewer(assignment.assignmentId), children: _jsxs("div", { className: "flex items-start justify-between", children: [_jsxs("div", { className: "flex-1", children: [_jsx("div", { className: "font-medium", children: assignment.reviewerName }), _jsx("div", { className: "text-xs text-gray-500", children: assignment.reviewerEmail }), getReviewerStatus(assignment), assignment.assignedBy && (_jsxs("div", { className: "mt-1 text-xs text-gray-400", children: ["Assigned by ", assignment.assignedBy] })), invitationErrors.has(assignment.assignmentId) && (_jsx("div", { className: "mt-1 text-xs text-red-600", children: invitationErrors.get(assignment.assignmentId) }))] }), !isLimitedPreviewUser && (_jsxs("div", { className: "flex items-center gap-2", onClick: (e) => e.stopPropagation(), children: [!assignment.invitationSentDate && (_jsx(Checkbox, { checked: selectedAssignments.has(assignment.assignmentId), onCheckedChange: (checked) => {
|
|
83
151
|
const newSet = new Set(selectedAssignments);
|
|
84
152
|
if (checked) {
|
|
85
153
|
newSet.add(assignment.assignmentId);
|
|
@@ -88,9 +156,61 @@ export function ReviewersPanel({ assignments, onAddReviewer, onRemoveReviewer, o
|
|
|
88
156
|
newSet.delete(assignment.assignmentId);
|
|
89
157
|
}
|
|
90
158
|
setSelectedAssignments(newSet);
|
|
91
|
-
} })), _jsx(Button, { variant: "ghost", size: "sm", onClick: (e) => {
|
|
159
|
+
} })), _jsx(Button, { variant: "ghost", size: "sm", className: "h-7 w-7 p-0", onClick: async (e) => {
|
|
160
|
+
e.stopPropagation();
|
|
161
|
+
const assignmentId = assignment.assignmentId;
|
|
162
|
+
setSendingInvitations(new Set([...sendingInvitations, assignmentId]));
|
|
163
|
+
const newErrors = new Map(invitationErrors);
|
|
164
|
+
newErrors.delete(assignmentId);
|
|
165
|
+
setInvitationErrors(newErrors);
|
|
166
|
+
try {
|
|
167
|
+
await onSendInvitations([assignmentId]);
|
|
168
|
+
}
|
|
169
|
+
catch (err) {
|
|
170
|
+
let errorMessage = err instanceof Error
|
|
171
|
+
? err.message
|
|
172
|
+
: "Failed to send invitation";
|
|
173
|
+
// Ensure errorMessage is a string, not JSON
|
|
174
|
+
if (typeof errorMessage !== "string") {
|
|
175
|
+
errorMessage = String(errorMessage);
|
|
176
|
+
}
|
|
177
|
+
// Check if there are individual assignment errors
|
|
178
|
+
if (err &&
|
|
179
|
+
typeof err === "object" &&
|
|
180
|
+
"assignmentErrors" in err) {
|
|
181
|
+
const assignmentErrorMap = err
|
|
182
|
+
.assignmentErrors;
|
|
183
|
+
if (assignmentErrorMap &&
|
|
184
|
+
assignmentErrorMap.has(assignmentId)) {
|
|
185
|
+
const specificError = assignmentErrorMap.get(assignmentId);
|
|
186
|
+
if (specificError &&
|
|
187
|
+
typeof specificError === "string") {
|
|
188
|
+
errorMessage = specificError;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
const newErrorMap = new Map(invitationErrors);
|
|
193
|
+
newErrorMap.set(assignmentId, errorMessage);
|
|
194
|
+
setInvitationErrors(newErrorMap);
|
|
195
|
+
}
|
|
196
|
+
finally {
|
|
197
|
+
const newSending = new Set(sendingInvitations);
|
|
198
|
+
newSending.delete(assignmentId);
|
|
199
|
+
setSendingInvitations(newSending);
|
|
200
|
+
}
|
|
201
|
+
}, disabled: loading ||
|
|
202
|
+
sendingInvitations.has(assignment.assignmentId), title: "Send invitation", children: sendingInvitations.has(assignment.assignmentId) ? (_jsx(Loader2, { className: "h-3 w-3 animate-spin" })) : (_jsx(Send, { className: "h-3 w-3" })) }), _jsx(Button, { variant: "ghost", size: "sm", className: "h-7 w-7 p-0", onClick: (e) => {
|
|
92
203
|
e.stopPropagation();
|
|
93
|
-
|
|
94
|
-
|
|
204
|
+
const reviewerName = assignment.reviewerName || assignment.reviewerEmail;
|
|
205
|
+
editContext?.confirm({
|
|
206
|
+
header: "Remove Reviewer",
|
|
207
|
+
message: `Are you sure you want to remove ${reviewerName} from this review?`,
|
|
208
|
+
acceptLabel: "Remove",
|
|
209
|
+
showCancel: true,
|
|
210
|
+
accept: async () => {
|
|
211
|
+
await onRemoveReviewer(assignment.assignmentId);
|
|
212
|
+
},
|
|
213
|
+
});
|
|
214
|
+
}, disabled: loading, children: _jsx(X, { className: "h-3 w-3" }) })] }))] }) }, assignment.assignmentId)))] })) })] }));
|
|
95
215
|
}
|
|
96
216
|
//# sourceMappingURL=ReviewersPanel.js.map
|