@brainfish-ai/components 0.22.10 → 0.22.11
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.
|
@@ -5,6 +5,7 @@ import parse from 'html-react-parser';
|
|
|
5
5
|
import { CaretDown, CaretUp, Backspace, CheckCircle, HandsClapping } from '@phosphor-icons/react';
|
|
6
6
|
import { Card, CardHeader, CardTitle, CardContent } from '../components/ui/card.js';
|
|
7
7
|
import { ScrollArea } from '../components/ui/scroll-area.js';
|
|
8
|
+
import { Spinner } from '../components/ui/spinner.js';
|
|
8
9
|
import { Button } from '../components/ui/button.js';
|
|
9
10
|
import { Tooltip, TooltipTrigger, TooltipContent } from '../components/ui/tooltip.js';
|
|
10
11
|
import { ButtonGroup } from '../components/ui/button-group.js';
|
|
@@ -58,6 +59,8 @@ const SuggestionsHeader = React.forwardRef(function SuggestionsHeader2({
|
|
|
58
59
|
sourceDescription,
|
|
59
60
|
currentArticleIndex,
|
|
60
61
|
totalArticles,
|
|
62
|
+
displayTotalArticles,
|
|
63
|
+
showActionButtons = true,
|
|
61
64
|
onNextArticle,
|
|
62
65
|
onPreviousArticle,
|
|
63
66
|
onRejectAllSuggestions,
|
|
@@ -71,7 +74,8 @@ const SuggestionsHeader = React.forwardRef(function SuggestionsHeader2({
|
|
|
71
74
|
const hasNextArticle = totalArticles > 0 && currentArticleIndex < totalArticles - 1;
|
|
72
75
|
const hasPreviousArticle = currentArticleIndex > 0;
|
|
73
76
|
const currentArticle = totalArticles === 0 ? 0 : currentArticleIndex + 1;
|
|
74
|
-
const
|
|
77
|
+
const totalArticlesForDisplay = displayTotalArticles ?? totalArticles;
|
|
78
|
+
const hasDisplayArticles = totalArticlesForDisplay > 0;
|
|
75
79
|
let status;
|
|
76
80
|
if (isNew) {
|
|
77
81
|
status = /* @__PURE__ */ React.createElement(StatusBadge, { variant: "success" }, "New");
|
|
@@ -88,7 +92,7 @@ const SuggestionsHeader = React.forwardRef(function SuggestionsHeader2({
|
|
|
88
92
|
className: "block px-0 text-subtle text-xs"
|
|
89
93
|
},
|
|
90
94
|
breadcrumb
|
|
91
|
-
)), /* @__PURE__ */ React.createElement("div", { className: "flex items-center" }, /* @__PURE__ */ React.createElement("p", { className: "text-xs text-foreground" }, /* @__PURE__ */ React.createElement("span", { "aria-hidden": "true" },
|
|
95
|
+
)), /* @__PURE__ */ React.createElement("div", { className: "flex items-center" }, /* @__PURE__ */ React.createElement("p", { className: "text-xs text-foreground" }, /* @__PURE__ */ React.createElement("span", { "aria-hidden": "true" }, hasDisplayArticles ? `${currentArticle}/${totalArticlesForDisplay}` : "0"), /* @__PURE__ */ React.createElement("span", { className: "sr-only", "aria-live": "polite" }, hasDisplayArticles ? `Article ${currentArticle} of ${totalArticlesForDisplay}` : "No articles")), /* @__PURE__ */ React.createElement(Tooltip, null, /* @__PURE__ */ React.createElement(TooltipTrigger, { asChild: true }, /* @__PURE__ */ React.createElement(
|
|
92
96
|
Button,
|
|
93
97
|
{
|
|
94
98
|
variant: "ghost",
|
|
@@ -118,7 +122,7 @@ const SuggestionsHeader = React.forwardRef(function SuggestionsHeader2({
|
|
|
118
122
|
},
|
|
119
123
|
sourceIcon && /* @__PURE__ */ React.createElement("span", { className: "shrink-0 flex items-center" }, sourceIcon),
|
|
120
124
|
/* @__PURE__ */ React.createElement("span", { className: "" }, sourceDescription)
|
|
121
|
-
) : /* @__PURE__ */ React.createElement("span", { className: "text-xs text-subtle" }, sourceDescription))), /* @__PURE__ */ React.createElement(ButtonGroup, { orientation: "horizontal", rounded: false, "aria-label": "Suggestion actions", className: "gap-1" }, /* @__PURE__ */ React.createElement(Button, { variant: "ghost", onClick: onRejectAllSuggestions }, /* @__PURE__ */ React.createElement(Backspace, { "aria-hidden": "true" }), "Reject"), /* @__PURE__ */ React.createElement(Button, { variant: "shadow", onClick: onAcceptAllSuggestions }, /* @__PURE__ */ React.createElement(CheckCircle, { "aria-hidden": "true" }), "Accept as draft"))));
|
|
125
|
+
) : /* @__PURE__ */ React.createElement("span", { className: "text-xs text-subtle" }, sourceDescription))), showActionButtons && /* @__PURE__ */ React.createElement(ButtonGroup, { orientation: "horizontal", rounded: false, "aria-label": "Suggestion actions", className: "gap-1" }, /* @__PURE__ */ React.createElement(Button, { variant: "ghost", onClick: onRejectAllSuggestions }, /* @__PURE__ */ React.createElement(Backspace, { "aria-hidden": "true" }), "Reject"), /* @__PURE__ */ React.createElement(Button, { variant: "shadow", onClick: onAcceptAllSuggestions }, /* @__PURE__ */ React.createElement(CheckCircle, { "aria-hidden": "true" }), "Accept as draft"))));
|
|
122
126
|
});
|
|
123
127
|
|
|
124
128
|
function countSuggestionsInRoot(root) {
|
|
@@ -144,6 +148,9 @@ const countSuggestionsInElement = (element) => {
|
|
|
144
148
|
function KnowledgeReviewPanel({
|
|
145
149
|
diffTitle,
|
|
146
150
|
items,
|
|
151
|
+
isLoading,
|
|
152
|
+
totalItemsCount,
|
|
153
|
+
showActionButtons = true,
|
|
147
154
|
children,
|
|
148
155
|
sourceIcon,
|
|
149
156
|
sourceDescription
|
|
@@ -159,7 +166,10 @@ function KnowledgeReviewPanel({
|
|
|
159
166
|
onSourceLinkClick,
|
|
160
167
|
breadcrumb
|
|
161
168
|
} = useReviewsSelection();
|
|
162
|
-
const
|
|
169
|
+
const hasItems = items.length > 0;
|
|
170
|
+
const resolvedIsLoading = isLoading ?? !hasItems;
|
|
171
|
+
const isLoadingState = resolvedIsLoading && !hasItems;
|
|
172
|
+
const isEmptyState = !resolvedIsLoading && !hasItems;
|
|
163
173
|
const title = loadingDiff ? "" : parse(loadedDiffDoc?.diffTitle ?? diffTitle ?? "");
|
|
164
174
|
const body = loadingDiff ? /* @__PURE__ */ React__default.createElement("div", { className: "text-muted-foreground" }, "Loading diff…") : loadedDiffDoc?.diffContent;
|
|
165
175
|
const titleSuggestionsCount = loadingDiff ? 0 : countSuggestions(loadedDiffDoc?.diffTitle ?? diffTitle);
|
|
@@ -177,8 +187,9 @@ function KnowledgeReviewPanel({
|
|
|
177
187
|
});
|
|
178
188
|
return () => cancelAnimationFrame(id);
|
|
179
189
|
}, [loadingDiff, loadedDiffDoc]);
|
|
180
|
-
const
|
|
190
|
+
const suggestionsCount = titleSuggestionsCount + bodySuggestionsCount;
|
|
181
191
|
const totalArticles = items.length;
|
|
192
|
+
const totalArticlesForDisplay = totalItemsCount ?? totalArticles;
|
|
182
193
|
const currentArticleIndex = selectedItem ? Math.max(
|
|
183
194
|
0,
|
|
184
195
|
items.findIndex((i) => i.id === selectedItem.id)
|
|
@@ -195,16 +206,18 @@ function KnowledgeReviewPanel({
|
|
|
195
206
|
}, [currentArticleIndex, items, setSelectedItem]);
|
|
196
207
|
const headerSourceIcon = selectedItem?.icon ?? sourceIcon;
|
|
197
208
|
const headerSourceDescription = selectedItem?.description ?? sourceDescription;
|
|
198
|
-
return /* @__PURE__ */ React__default.createElement(Card, { className: "py-6 pl-4", "data-name": "knowledge-reviews" }, /* @__PURE__ */ React__default.createElement(ScrollArea, { className: "h-[calc(var(--knowledge-review-scroll-height)-50px)] pr-8" }, /* @__PURE__ */ React__default.createElement(CardHeader, { className: "p-0" },
|
|
209
|
+
return /* @__PURE__ */ React__default.createElement(Card, { className: "py-6 pl-4", "data-name": "knowledge-reviews" }, /* @__PURE__ */ React__default.createElement(ScrollArea, { className: "h-[calc(var(--knowledge-review-scroll-height)-50px)] pr-8" }, /* @__PURE__ */ React__default.createElement(CardHeader, { className: "p-0" }, hasItems && /* @__PURE__ */ React__default.createElement(CardTitle, { className: "border-b border-dark-300 mb-6 pb-2 font-normal" }, /* @__PURE__ */ React__default.createElement(
|
|
199
210
|
SuggestionsHeader,
|
|
200
211
|
{
|
|
201
212
|
title,
|
|
202
213
|
isNew: loadedDiffDoc?.isNew ?? false,
|
|
203
|
-
suggestionsCount
|
|
214
|
+
suggestionsCount,
|
|
204
215
|
sourceIcon: headerSourceIcon,
|
|
205
216
|
sourceDescription: headerSourceDescription,
|
|
206
217
|
currentArticleIndex,
|
|
207
218
|
totalArticles,
|
|
219
|
+
displayTotalArticles: totalArticlesForDisplay,
|
|
220
|
+
showActionButtons,
|
|
208
221
|
onNextArticle,
|
|
209
222
|
onPreviousArticle,
|
|
210
223
|
onRejectAllSuggestions,
|
|
@@ -213,7 +226,7 @@ function KnowledgeReviewPanel({
|
|
|
213
226
|
onSourceLinkClick,
|
|
214
227
|
breadcrumb
|
|
215
228
|
}
|
|
216
|
-
))), /* @__PURE__ */ React__default.createElement(CardContent, { className: "p-0 [&_ol]:!pl-16 [&_ul]:!pl-16" }, /* @__PURE__ */ React__default.createElement("div", { "aria-hidden": "true", className: "sr-only", hidden: true }, children), isEmptyState ? /* @__PURE__ */ React__default.createElement("div", { className: "flex flex-col items-center justify-center gap-4 text-center h-[50dvh]" }, /* @__PURE__ */ React__default.createElement(HandsClapping, { className: "text-muted-foreground", size: 32, weight: "fill" }), /* @__PURE__ */ React__default.createElement("p", { className: "text-base font-medium text-foreground" }, "All up to date. Well done, mate.")) : /* @__PURE__ */ React__default.createElement("div", { ref: bodyRef }, body))));
|
|
229
|
+
))), /* @__PURE__ */ React__default.createElement(CardContent, { className: "p-0 [&_ol]:!pl-16 [&_ul]:!pl-16" }, /* @__PURE__ */ React__default.createElement("div", { "aria-hidden": "true", className: "sr-only", hidden: true }, children), isLoadingState ? /* @__PURE__ */ React__default.createElement("div", { className: "flex flex-col items-center justify-center gap-4 text-center h-[50dvh] text-muted-foreground" }, /* @__PURE__ */ React__default.createElement(Spinner, { className: "size-8" }), /* @__PURE__ */ React__default.createElement("p", { className: "text-base font-medium" }, "Loading suggestions...")) : isEmptyState ? /* @__PURE__ */ React__default.createElement("div", { className: "flex flex-col items-center justify-center gap-4 text-center h-[50dvh]" }, /* @__PURE__ */ React__default.createElement(HandsClapping, { className: "text-muted-foreground", size: 32, weight: "fill" }), /* @__PURE__ */ React__default.createElement("p", { className: "text-base font-medium text-foreground" }, "All up to date. Well done, mate.")) : /* @__PURE__ */ React__default.createElement("div", { ref: bodyRef }, body))));
|
|
217
230
|
}
|
|
218
231
|
|
|
219
232
|
const SCROLL_HEIGHT_VAR = "--knowledge-review-scroll-height";
|
|
@@ -222,6 +235,9 @@ const KnowledgeReviewSceneInner = React__default.forwardRef(
|
|
|
222
235
|
diffTitle = "Knowledge Review",
|
|
223
236
|
children,
|
|
224
237
|
items,
|
|
238
|
+
isLoading,
|
|
239
|
+
totalItemsCount,
|
|
240
|
+
showActionButtons = true,
|
|
225
241
|
className,
|
|
226
242
|
onApproveAllSuggestions,
|
|
227
243
|
onRejectAllSuggestions,
|
|
@@ -257,6 +273,8 @@ const KnowledgeReviewSceneInner = React__default.forwardRef(
|
|
|
257
273
|
observer.observe(cardEl);
|
|
258
274
|
return () => observer.disconnect();
|
|
259
275
|
}, []);
|
|
276
|
+
const resolvedIsLoading = isLoading ?? items.length === 0;
|
|
277
|
+
const isLoadingItems = resolvedIsLoading && items.length === 0;
|
|
260
278
|
return /* @__PURE__ */ React__default.createElement(Card, { className: cn("h-full", className) }, /* @__PURE__ */ React__default.createElement(CardContent, { className: "p-4 lg:p-8 h-full" }, /* @__PURE__ */ React__default.createElement(
|
|
261
279
|
"div",
|
|
262
280
|
{
|
|
@@ -265,12 +283,15 @@ const KnowledgeReviewSceneInner = React__default.forwardRef(
|
|
|
265
283
|
style: { [SCROLL_HEIGHT_VAR]: "100px" },
|
|
266
284
|
...props
|
|
267
285
|
},
|
|
268
|
-
/* @__PURE__ */ React__default.createElement(ScrollArea, { className: "h-[calc(var(--knowledge-review-scroll-height))] min-w-80 lg:block hidden" }, /* @__PURE__ */ React__default.createElement(ReviewList, { items })),
|
|
286
|
+
/* @__PURE__ */ React__default.createElement(ScrollArea, { className: "h-[calc(var(--knowledge-review-scroll-height))] min-w-80 lg:block hidden" }, isLoadingItems ? /* @__PURE__ */ React__default.createElement("div", { className: "flex h-full min-h-96 items-center justify-center text-muted-foreground" }, /* @__PURE__ */ React__default.createElement(Spinner, { className: "size-6" })) : /* @__PURE__ */ React__default.createElement(ReviewList, { items })),
|
|
269
287
|
/* @__PURE__ */ React__default.createElement(
|
|
270
288
|
KnowledgeReviewPanel,
|
|
271
289
|
{
|
|
272
290
|
diffTitle,
|
|
273
291
|
items,
|
|
292
|
+
isLoading: resolvedIsLoading,
|
|
293
|
+
totalItemsCount,
|
|
294
|
+
showActionButtons,
|
|
274
295
|
sourceIcon,
|
|
275
296
|
sourceDescription
|
|
276
297
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"knowledge-review.js","sources":["../../../src/scenes/knowledge-review/diff-loader.tsx","../../../src/scenes/knowledge-review/suggestions-header/suggestions-header.tsx","../../../src/lib/countSuggestions.ts","../../../src/scenes/knowledge-review/knowledge-review-panel.tsx","../../../src/scenes/knowledge-review/scene.tsx"],"sourcesContent":["import { useCallback, useEffect } from 'react';\n\nimport type { LoadedDiffDoc } from './context';\nimport { useReviewsSelection } from './context';\n\nexport type KnowledgeReviewDiffLoaderProps = {\n /** Called when selectedItem changes. Return diff payload or null. */\n fetchDiffForItem: (itemId: string) => Promise<LoadedDiffDoc | null>;\n};\n\n/**\n * Listens to selectedItem from context and fetches diff via the provided callback.\n * Owns loading state and context updates; host (Storybook or Platform) supplies fetch logic.\n */\nexport function KnowledgeReviewDiffLoader({ fetchDiffForItem }: KnowledgeReviewDiffLoaderProps) {\n const { selectedItem, setLoadedDiffDoc, setLoadingDiff } = useReviewsSelection();\n\n const loadDiffForItem = useCallback(\n async (itemId: string, signal: AbortSignal) => {\n setLoadingDiff(true);\n setLoadedDiffDoc(null);\n\n try {\n const doc = await fetchDiffForItem(itemId);\n if (signal.aborted) return;\n setLoadedDiffDoc(doc);\n } catch (error) {\n if (signal.aborted) return;\n console.error('Failed to fetch diff:', error);\n setLoadedDiffDoc(null);\n } finally {\n if (!signal.aborted) {\n setLoadingDiff(false);\n }\n }\n },\n [fetchDiffForItem, setLoadedDiffDoc, setLoadingDiff],\n );\n\n const selectedId = selectedItem?.id;\n\n useEffect(() => {\n if (!selectedId) {\n setLoadedDiffDoc(null);\n setLoadingDiff(false);\n\n return;\n }\n\n const abortController = new AbortController();\n void loadDiffForItem(selectedId, abortController.signal);\n\n return () => {\n abortController.abort();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedId, loadDiffForItem]);\n\n return null;\n}\n","import { CaretDown, CaretUp, Backspace, CheckCircle } from '@phosphor-icons/react';\nimport * as React from 'react';\n\nimport { EditCount } from '../review-list/edit-count';\n\nimport { Button } from '@/components/ui/button';\nimport { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';\nimport { ButtonGroup } from '@/components/ui/button-group';\nimport { cn } from '@/lib/utils';\nimport { dark } from '@/colors/dark';\nimport { StatusBadge } from '@/components/convos/status-badge';\n\nexport interface SuggestionsHeaderProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'title'> {\n title: React.ReactNode;\n isNew: boolean;\n suggestionsCount: number;\n sourceIcon: React.ReactNode;\n sourceDescription: string | null;\n currentArticleIndex: number;\n totalArticles: number;\n onNextArticle: () => void;\n onPreviousArticle: () => void;\n onRejectAllSuggestions: () => void;\n onAcceptAllSuggestions: () => void;\n breadcrumb?: string;\n onOpenArticleLink?: () => void;\n onSourceLinkClick?: () => void;\n}\n\nexport const SuggestionsHeader = React.forwardRef<HTMLDivElement, SuggestionsHeaderProps>(function SuggestionsHeader(\n {\n title,\n isNew,\n suggestionsCount,\n sourceIcon,\n sourceDescription,\n currentArticleIndex,\n totalArticles,\n onNextArticle,\n onPreviousArticle,\n onRejectAllSuggestions,\n onAcceptAllSuggestions,\n breadcrumb,\n onOpenArticleLink,\n onSourceLinkClick,\n className,\n ...props\n },\n ref,\n) {\n const hasNextArticle = totalArticles > 0 && currentArticleIndex < totalArticles - 1;\n const hasPreviousArticle = currentArticleIndex > 0;\n const currentArticle = totalArticles === 0 ? 0 : currentArticleIndex + 1;\n const hasArticles = totalArticles > 0;\n\n let status: React.ReactNode | undefined;\n if (isNew) {\n status = <StatusBadge variant=\"success\">New</StatusBadge>;\n } else if (suggestionsCount) {\n status = <EditCount count={suggestionsCount} />;\n }\n\n return (\n <div ref={ref} className={cn('flex flex-col gap-4', className)} {...props}>\n {/* Header + Navigation */}\n <div className=\"flex justify-between items-center\">\n <h1 className=\"heading-lg\">\n {title}\n {/* Breadcrumbs */}\n {onOpenArticleLink && breadcrumb && (\n <Button\n variant=\"link\"\n size=\"sm\"\n onClick={onOpenArticleLink}\n aria-label=\"Open article\"\n className=\"block px-0 text-subtle text-xs\"\n >\n {breadcrumb}\n </Button>\n )}\n </h1>\n {/* up/down carets */}\n <div className=\"flex items-center\">\n <p className=\"text-xs text-foreground\">\n <span aria-hidden=\"true\">{hasArticles ? `${currentArticle}/${totalArticles}` : '0'}</span>\n <span className=\"sr-only\" aria-live=\"polite\">\n {hasArticles ? `Article ${currentArticle} of ${totalArticles}` : 'No articles'}\n </span>\n </p>\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n disabled={!hasNextArticle}\n onClick={onNextArticle}\n aria-label=\"Go to next article\"\n >\n <CaretDown aria-hidden=\"true\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent side=\"bottom\" borderColor=\"transparent\" background={dark[900]} textColor={dark[100]}>\n Next Article\n </TooltipContent>\n </Tooltip>\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n disabled={!hasPreviousArticle}\n onClick={onPreviousArticle}\n aria-label=\"Go to previous article\"\n >\n <CaretUp aria-hidden=\"true\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent side=\"top\" borderColor=\"transparent\" background={dark[900]} textColor={dark[100]}>\n Previous Article\n </TooltipContent>\n </Tooltip>\n </div>\n </div>\n\n {/* Status, Source + Actions */}\n <div className=\"flex-1 px-2 pb-2 flex justify-between items-center\">\n <div className=\"flex items-center gap-2\">\n {status}\n {sourceDescription &&\n (onSourceLinkClick ? (\n <Button\n variant=\"link\"\n onClick={onSourceLinkClick}\n aria-label=\"Open source\"\n className=\"[&_svg]:size-4 text-xs text-subtle gap-1\"\n >\n {sourceIcon && <span className=\"shrink-0 flex items-center\">{sourceIcon}</span>}\n <span className=\"\">{sourceDescription}</span>\n </Button>\n ) : (\n <span className=\"text-xs text-subtle\">{sourceDescription}</span>\n ))}\n </div>\n <ButtonGroup orientation=\"horizontal\" rounded={false} aria-label=\"Suggestion actions\" className=\"gap-1\">\n <Button variant=\"ghost\" onClick={onRejectAllSuggestions}>\n <Backspace aria-hidden=\"true\" />\n Reject\n </Button>\n <Button variant=\"shadow\" onClick={onAcceptAllSuggestions}>\n <CheckCircle aria-hidden=\"true\" />\n Accept as draft\n </Button>\n </ButtonGroup>\n </div>\n </div>\n );\n});\n","function countSuggestionsInRoot(root: Document | Element): number {\n const adjacentPairs = root.querySelectorAll('del + ins');\n const standaloneIns = root.querySelectorAll('ins:not(del + ins)');\n const allDel = root.querySelectorAll('del');\n const standaloneDel = Array.from(allDel).filter((del) => del.nextElementSibling?.tagName !== 'INS');\n\n return adjacentPairs.length + standaloneIns.length + standaloneDel.length;\n}\n\n/** Count suggestions in an HTML string (for title or raw HTML content). */\nexport const countSuggestions = (htmlString: string) => {\n if (!htmlString || typeof DOMParser === 'undefined') {\n return 0;\n }\n const parser = new DOMParser();\n const doc = parser.parseFromString(htmlString, 'text/html');\n\n return countSuggestionsInRoot(doc);\n};\n\n/** Count suggestions inside a DOM element (for rendered ReactNode body content). */\nexport const countSuggestionsInElement = (element: Element | null) => {\n if (!element) return 0;\n\n return countSuggestionsInRoot(element);\n};\n","import React, { useCallback, useEffect, useRef, useState } from 'react';\nimport parse from 'html-react-parser';\nimport { HandsClapping } from '@phosphor-icons/react';\n\nimport { useReviewsSelection } from './context';\nimport { SuggestionsHeader } from './suggestions-header';\nimport type { ReviewListItemProps } from './review-list';\n\nimport { countSuggestions, countSuggestionsInElement } from '@/lib/countSuggestions';\nimport { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';\nimport { ScrollArea } from '@/components/ui/scroll-area';\n\nexport type KnowledgeReviewPanelProps = {\n diffTitle: string;\n items: ReviewListItemProps[];\n children?: React.ReactNode;\n sourceIcon: React.ReactNode;\n sourceDescription: string | null;\n};\n\n/**\n * Panel that shows the selected diff (title + content), suggestion count, and article nav.\n * Must be used inside ReviewsSelectionProvider. Expects --knowledge-review-scroll-height\n * to be set by a parent for ScrollArea height.\n */\nexport function KnowledgeReviewPanel({\n diffTitle,\n items,\n children,\n sourceIcon,\n sourceDescription,\n}: KnowledgeReviewPanelProps) {\n const {\n selectedItem,\n setSelectedItem,\n loadedDiffDoc,\n loadingDiff,\n onApproveAllSuggestions,\n onRejectAllSuggestions,\n onOpenArticleLink,\n onSourceLinkClick,\n breadcrumb,\n } = useReviewsSelection();\n\n const isEmptyState = items.length === 0;\n\n const title = loadingDiff ? '' : parse(loadedDiffDoc?.diffTitle ?? diffTitle ?? '');\n const body = loadingDiff ? <div className=\"text-muted-foreground\">Loading diff…</div> : loadedDiffDoc?.diffContent;\n\n const titleSuggestionsCount = loadingDiff ? 0 : countSuggestions(loadedDiffDoc?.diffTitle ?? diffTitle);\n\n const bodyRef = useRef<HTMLDivElement>(null);\n const [bodySuggestionsCount, setBodySuggestionsCount] = useState(0);\n useEffect(() => {\n if (loadingDiff || !loadedDiffDoc) {\n setBodySuggestionsCount(0);\n\n return;\n }\n const el = bodyRef.current;\n if (!el) return;\n const id = requestAnimationFrame(() => {\n setBodySuggestionsCount(countSuggestionsInElement(el));\n });\n\n return () => cancelAnimationFrame(id);\n }, [loadingDiff, loadedDiffDoc]);\n\n const totalSuggestionsCount = titleSuggestionsCount + bodySuggestionsCount;\n\n const totalArticles = items.length;\n const currentArticleIndex = selectedItem\n ? Math.max(\n 0,\n items.findIndex((i) => i.id === selectedItem.id),\n )\n : 0;\n\n const onNextArticle = useCallback(() => {\n if (currentArticleIndex < totalArticles - 1) {\n setSelectedItem(items[currentArticleIndex + 1] ?? null);\n }\n }, [currentArticleIndex, items, setSelectedItem, totalArticles]);\n\n const onPreviousArticle = useCallback(() => {\n if (currentArticleIndex > 0) {\n setSelectedItem(items[currentArticleIndex - 1] ?? null);\n }\n }, [currentArticleIndex, items, setSelectedItem]);\n\n const headerSourceIcon = selectedItem?.icon ?? sourceIcon;\n const headerSourceDescription = selectedItem?.description ?? sourceDescription;\n\n return (\n <Card className=\"py-6 pl-4\" data-name=\"knowledge-reviews\">\n <ScrollArea className=\"h-[calc(var(--knowledge-review-scroll-height)-50px)] pr-8\">\n <CardHeader className=\"p-0\">\n {!isEmptyState && (\n <CardTitle className=\"border-b border-dark-300 mb-6 pb-2 font-normal\">\n <SuggestionsHeader\n title={title}\n isNew={loadedDiffDoc?.isNew ?? false}\n suggestionsCount={totalSuggestionsCount}\n sourceIcon={headerSourceIcon}\n sourceDescription={headerSourceDescription}\n currentArticleIndex={currentArticleIndex}\n totalArticles={totalArticles}\n onNextArticle={onNextArticle}\n onPreviousArticle={onPreviousArticle}\n onRejectAllSuggestions={onRejectAllSuggestions}\n onAcceptAllSuggestions={onApproveAllSuggestions}\n onOpenArticleLink={onOpenArticleLink}\n onSourceLinkClick={onSourceLinkClick}\n breadcrumb={breadcrumb}\n />\n </CardTitle>\n )}\n </CardHeader>\n <CardContent className=\"p-0 [&_ol]:!pl-16 [&_ul]:!pl-16\">\n {/* Mount point for children (e.g. KnowledgeReviewDiffLoader). Kept in DOM so its effects run; hidden because it has no UI. */}\n <div aria-hidden=\"true\" className=\"sr-only\" hidden>\n {children}\n </div>\n {isEmptyState ? (\n <div className=\"flex flex-col items-center justify-center gap-4 text-center h-[50dvh]\">\n <HandsClapping className=\"text-muted-foreground\" size={32} weight=\"fill\" />\n <p className=\"text-base font-medium text-foreground\">All up to date. Well done, mate.</p>\n </div>\n ) : (\n <div ref={bodyRef}>{body}</div>\n )}\n </CardContent>\n </ScrollArea>\n </Card>\n );\n}\n","import React, { useEffect, useImperativeHandle, useRef } from 'react';\n\nimport { useReviewsSelection } from './context';\nimport { ReviewList, ReviewListItemProps, ReviewsSelectionProvider } from './review-list';\nimport { KnowledgeReviewPanel } from './knowledge-review-panel';\n\nimport { Card, CardContent } from '@/components/ui/card';\nimport { ScrollArea } from '@/components/ui/scroll-area';\nimport { cn } from '@/lib/utils';\n\nimport './knowledge-review.css';\n\nconst SCROLL_HEIGHT_VAR = '--knowledge-review-scroll-height';\n\nexport type KnowledgeReviewSceneHandle = {\n selectedItem: ReviewListItemProps | null;\n setSelectedItem: (item: ReviewListItemProps | null) => void;\n};\n\nexport type KnowledgeReviewSceneProps = {\n diffTitle?: string;\n children: React.ReactNode;\n items: ReviewListItemProps[];\n className?: string;\n onApproveAllSuggestions: () => void;\n onRejectAllSuggestions: () => void;\n onOpenArticleLink?: () => void;\n onSourceLinkClick?: () => void;\n breadcrumb?: string;\n sourceIcon: React.ReactNode;\n sourceDescription: string | null;\n};\n\nconst KnowledgeReviewSceneInner = React.forwardRef<KnowledgeReviewSceneHandle, KnowledgeReviewSceneProps>(\n function KnowledgeReviewSceneInner(\n {\n diffTitle = 'Knowledge Review',\n children,\n items,\n className,\n onApproveAllSuggestions,\n onRejectAllSuggestions,\n onOpenArticleLink,\n onSourceLinkClick,\n breadcrumb,\n sourceIcon,\n sourceDescription,\n ...props\n },\n ref,\n ) {\n const innerRef = useRef<HTMLDivElement>(null);\n const { selectedItem, setSelectedItem } = useReviewsSelection();\n\n useImperativeHandle(\n ref,\n () => ({\n selectedItem,\n setSelectedItem,\n }),\n [selectedItem, setSelectedItem],\n );\n\n useEffect(() => {\n const cardEl = innerRef.current;\n if (!cardEl) return;\n\n const updateHeight = () => {\n const { height } = cardEl.getBoundingClientRect();\n cardEl.style.setProperty(SCROLL_HEIGHT_VAR, `${height}px`);\n };\n\n updateHeight();\n\n if (typeof ResizeObserver !== 'function') {\n return;\n }\n\n const observer = new ResizeObserver(updateHeight);\n observer.observe(cardEl);\n\n return () => observer.disconnect();\n }, []);\n\n return (\n <Card className={cn('h-full', className)}>\n <CardContent className=\"p-4 lg:p-8 h-full\">\n <div\n ref={innerRef}\n className=\"grid xs:max-lg:grid-cols-1 lg:grid-cols-[1fr_4fr] gap-6 min-h-96 h-full\"\n style={{ [SCROLL_HEIGHT_VAR]: '100px' } as React.CSSProperties}\n {...props}\n >\n <ScrollArea className=\"h-[calc(var(--knowledge-review-scroll-height))] min-w-80 lg:block hidden\">\n <ReviewList items={items} />\n </ScrollArea>\n <KnowledgeReviewPanel\n diffTitle={diffTitle}\n items={items}\n sourceIcon={sourceIcon}\n sourceDescription={sourceDescription}\n >\n {children}\n </KnowledgeReviewPanel>\n </div>\n </CardContent>\n </Card>\n );\n },\n);\n\nexport const KnowledgeReviewScene = React.forwardRef<KnowledgeReviewSceneHandle, KnowledgeReviewSceneProps>(\n function KnowledgeReviewScene(props, ref) {\n const { items, onApproveAllSuggestions, onRejectAllSuggestions, onOpenArticleLink, onSourceLinkClick, breadcrumb } =\n props;\n\n return (\n <ReviewsSelectionProvider\n defaultSelectedItem={items.find((m) => m.isSelected) ?? null}\n onApproveAllSuggestions={onApproveAllSuggestions}\n onRejectAllSuggestions={onRejectAllSuggestions}\n onOpenArticleLink={onOpenArticleLink}\n onSourceLinkClick={onSourceLinkClick}\n breadcrumb={breadcrumb}\n >\n <KnowledgeReviewSceneInner {...props} ref={ref} />\n </ReviewsSelectionProvider>\n );\n },\n);\n"],"names":["SuggestionsHeader","React","KnowledgeReviewSceneInner","KnowledgeReviewScene"],"mappings":";;;;;;;;;;;;;;AAcO,SAAS,yBAAA,CAA0B,EAAE,gBAAA,EAAiB,EAAmC;AAC9F,EAAA,MAAM,EAAE,YAAA,EAAc,gBAAA,EAAkB,cAAA,KAAmB,mBAAA,EAAoB;AAE/E,EAAA,MAAM,eAAA,GAAkB,WAAA;AAAA,IACtB,OAAO,QAAgB,MAAA,KAAwB;AAC7C,MAAA,cAAA,CAAe,IAAI,CAAA;AACnB,MAAA,gBAAA,CAAiB,IAAI,CAAA;AAErB,MAAA,IAAI;AACF,QAAA,MAAM,GAAA,GAAM,MAAM,gBAAA,CAAiB,MAAM,CAAA;AACzC,QAAA,IAAI,OAAO,OAAA,EAAS;AACpB,QAAA,gBAAA,CAAiB,GAAG,CAAA;AAAA,MACtB,SAAS,KAAA,EAAO;AACd,QAAA,IAAI,OAAO,OAAA,EAAS;AACpB,QAAA,OAAA,CAAQ,KAAA,CAAM,yBAAyB,KAAK,CAAA;AAC5C,QAAA,gBAAA,CAAiB,IAAI,CAAA;AAAA,MACvB,CAAA,SAAE;AACA,QAAA,IAAI,CAAC,OAAO,OAAA,EAAS;AACnB,UAAA,cAAA,CAAe,KAAK,CAAA;AAAA,QACtB;AAAA,MACF;AAAA,IACF,CAAA;AAAA,IACA,CAAC,gBAAA,EAAkB,gBAAA,EAAkB,cAAc;AAAA,GACrD;AAEA,EAAA,MAAM,aAAa,YAAA,EAAc,EAAA;AAEjC,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,UAAA,EAAY;AACf,MAAA,gBAAA,CAAiB,IAAI,CAAA;AACrB,MAAA,cAAA,CAAe,KAAK,CAAA;AAEpB,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,eAAA,GAAkB,IAAI,eAAA,EAAgB;AAC5C,IAAA,KAAK,eAAA,CAAgB,UAAA,EAAY,eAAA,CAAgB,MAAM,CAAA;AAEvD,IAAA,OAAO,MAAM;AACX,MAAA,eAAA,CAAgB,KAAA,EAAM;AAAA,IACxB,CAAA;AAAA,EAEF,CAAA,EAAG,CAAC,UAAA,EAAY,eAAe,CAAC,CAAA;AAEhC,EAAA,OAAO,IAAA;AACT;;AC9BO,MAAM,iBAAA,GAAoB,KAAA,CAAM,UAAA,CAAmD,SAASA,kBAAAA,CACjG;AAAA,EACE,KAAA;AAAA,EACA,KAAA;AAAA,EACA,gBAAA;AAAA,EACA,UAAA;AAAA,EACA,iBAAA;AAAA,EACA,mBAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,iBAAA;AAAA,EACA,sBAAA;AAAA,EACA,sBAAA;AAAA,EACA,UAAA;AAAA,EACA,iBAAA;AAAA,EACA,iBAAA;AAAA,EACA,SAAA;AAAA,EACA,GAAG;AACL,CAAA,EACA,GAAA,EACA;AACA,EAAA,MAAM,cAAA,GAAiB,aAAA,GAAgB,CAAA,IAAK,mBAAA,GAAsB,aAAA,GAAgB,CAAA;AAClF,EAAA,MAAM,qBAAqB,mBAAA,GAAsB,CAAA;AACjD,EAAA,MAAM,cAAA,GAAiB,aAAA,KAAkB,CAAA,GAAI,CAAA,GAAI,mBAAA,GAAsB,CAAA;AACvE,EAAA,MAAM,cAAc,aAAA,GAAgB,CAAA;AAEpC,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI,KAAA,EAAO;AACT,IAAA,MAAA,mBAAS,KAAA,CAAA,aAAA,CAAC,WAAA,EAAA,EAAY,OAAA,EAAQ,SAAA,EAAA,EAAU,KAAG,CAAA;AAAA,EAC7C,WAAW,gBAAA,EAAkB;AAC3B,IAAA,MAAA,mBAAS,KAAA,CAAA,aAAA,CAAC,SAAA,EAAA,EAAU,KAAA,EAAO,gBAAA,EAAkB,CAAA;AAAA,EAC/C;AAEA,EAAA,uBACE,KAAA,CAAA,aAAA,CAAC,SAAI,GAAA,EAAU,SAAA,EAAW,GAAG,qBAAA,EAAuB,SAAS,GAAI,GAAG,KAAA,EAAA,sCAEjE,KAAA,EAAA,EAAI,SAAA,EAAU,uDACb,KAAA,CAAA,aAAA,CAAC,IAAA,EAAA,EAAG,WAAU,YAAA,EAAA,EACX,KAAA,EAEA,qBAAqB,UAAA,oBACpB,KAAA,CAAA,aAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,OAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAK,IAAA;AAAA,MACL,OAAA,EAAS,iBAAA;AAAA,MACT,YAAA,EAAW,cAAA;AAAA,MACX,SAAA,EAAU;AAAA,KAAA;AAAA,IAET;AAAA,GAGP,CAAA,kBAEA,KAAA,CAAA,aAAA,CAAC,SAAI,SAAA,EAAU,mBAAA,EAAA,sCACZ,GAAA,EAAA,EAAE,SAAA,EAAU,6CACX,KAAA,CAAA,aAAA,CAAC,MAAA,EAAA,EAAK,eAAY,MAAA,EAAA,EAAQ,WAAA,GAAc,GAAG,cAAc,CAAA,CAAA,EAAI,aAAa,CAAA,CAAA,GAAK,GAAI,CAAA,kBACnF,KAAA,CAAA,aAAA,CAAC,UAAK,SAAA,EAAU,SAAA,EAAU,aAAU,QAAA,EAAA,EACjC,WAAA,GAAc,WAAW,cAAc,CAAA,IAAA,EAAO,aAAa,CAAA,CAAA,GAAK,aACnE,CACF,CAAA,kBACA,KAAA,CAAA,aAAA,CAAC,+BACC,KAAA,CAAA,aAAA,CAAC,cAAA,EAAA,EAAe,SAAO,IAAA,EAAA,kBACrB,KAAA,CAAA,aAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,OAAA,EAAQ,OAAA;AAAA,MACR,IAAA,EAAK,MAAA;AAAA,MACL,UAAU,CAAC,cAAA;AAAA,MACX,OAAA,EAAS,aAAA;AAAA,MACT,YAAA,EAAW;AAAA,KAAA;AAAA,oBAEX,KAAA,CAAA,aAAA,CAAC,SAAA,EAAA,EAAU,aAAA,EAAY,MAAA,EAAO;AAAA,GAElC,CAAA,kBACA,KAAA,CAAA,aAAA,CAAC,cAAA,EAAA,EAAe,IAAA,EAAK,UAAS,WAAA,EAAY,aAAA,EAAc,UAAA,EAAY,IAAA,CAAK,GAAG,CAAA,EAAG,WAAW,IAAA,CAAK,GAAG,CAAA,EAAA,EAAG,cAErG,CACF,CAAA,sCACC,OAAA,EAAA,IAAA,kBACC,KAAA,CAAA,aAAA,CAAC,cAAA,EAAA,EAAe,OAAA,EAAO,IAAA,EAAA,kBACrB,KAAA,CAAA,aAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,OAAA,EAAQ,OAAA;AAAA,MACR,IAAA,EAAK,MAAA;AAAA,MACL,UAAU,CAAC,kBAAA;AAAA,MACX,OAAA,EAAS,iBAAA;AAAA,MACT,YAAA,EAAW;AAAA,KAAA;AAAA,oBAEX,KAAA,CAAA,aAAA,CAAC,OAAA,EAAA,EAAQ,aAAA,EAAY,MAAA,EAAO;AAAA,GAEhC,CAAA,kBACA,KAAA,CAAA,aAAA,CAAC,cAAA,EAAA,EAAe,IAAA,EAAK,KAAA,EAAM,WAAA,EAAY,aAAA,EAAc,UAAA,EAAY,IAAA,CAAK,GAAG,CAAA,EAAG,WAAW,IAAA,CAAK,GAAG,CAAA,EAAA,EAAG,kBAElG,CACF,CACF,CACF,CAAA,sCAGC,KAAA,EAAA,EAAI,SAAA,EAAU,oDAAA,EAAA,kBACb,KAAA,CAAA,aAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,yBAAA,EAAA,EACZ,MAAA,EACA,sBACE,iBAAA,mBACC,KAAA,CAAA,aAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,OAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS,iBAAA;AAAA,MACT,YAAA,EAAW,aAAA;AAAA,MACX,SAAA,EAAU;AAAA,KAAA;AAAA,IAET,UAAA,oBAAc,KAAA,CAAA,aAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,gCAA8B,UAAW,CAAA;AAAA,oBACxE,KAAA,CAAA,aAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,EAAA,EAAA,EAAI,iBAAkB;AAAA,GACxC,uCAEC,MAAA,EAAA,EAAK,SAAA,EAAU,yBAAuB,iBAAkB,CAAA,CAE/D,mBACA,KAAA,CAAA,aAAA,CAAC,WAAA,EAAA,EAAY,aAAY,YAAA,EAAa,OAAA,EAAS,OAAO,YAAA,EAAW,oBAAA,EAAqB,WAAU,OAAA,EAAA,kBAC9F,KAAA,CAAA,aAAA,CAAC,UAAO,OAAA,EAAQ,OAAA,EAAQ,SAAS,sBAAA,EAAA,kBAC/B,KAAA,CAAA,aAAA,CAAC,aAAU,aAAA,EAAY,MAAA,EAAO,GAAE,QAElC,CAAA,sCACC,MAAA,EAAA,EAAO,OAAA,EAAQ,UAAS,OAAA,EAAS,sBAAA,EAAA,sCAC/B,WAAA,EAAA,EAAY,aAAA,EAAY,QAAO,CAAA,EAAE,iBAEpC,CACF,CACF,CACF,CAAA;AAEJ,CAAC,CAAA;;AC5JD,SAAS,uBAAuB,IAAA,EAAkC;AAChE,EAAA,MAAM,aAAA,GAAgB,IAAA,CAAK,gBAAA,CAAiB,WAAW,CAAA;AACvD,EAAA,MAAM,aAAA,GAAgB,IAAA,CAAK,gBAAA,CAAiB,oBAAoB,CAAA;AAChE,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,gBAAA,CAAiB,KAAK,CAAA;AAC1C,EAAA,MAAM,aAAA,GAAgB,KAAA,CAAM,IAAA,CAAK,MAAM,CAAA,CAAE,MAAA,CAAO,CAAC,GAAA,KAAQ,GAAA,CAAI,kBAAA,EAAoB,OAAA,KAAY,KAAK,CAAA;AAElG,EAAA,OAAO,aAAA,CAAc,MAAA,GAAS,aAAA,CAAc,MAAA,GAAS,aAAA,CAAc,MAAA;AACrE;AAGO,MAAM,gBAAA,GAAmB,CAAC,UAAA,KAAuB;AACtD,EAAA,IAAI,CAAC,UAAA,IAAc,OAAO,SAAA,KAAc,WAAA,EAAa;AACnD,IAAA,OAAO,CAAA;AAAA,EACT;AACA,EAAA,MAAM,MAAA,GAAS,IAAI,SAAA,EAAU;AAC7B,EAAA,MAAM,GAAA,GAAM,MAAA,CAAO,eAAA,CAAgB,UAAA,EAAY,WAAW,CAAA;AAE1D,EAAA,OAAO,uBAAuB,GAAG,CAAA;AACnC,CAAA;AAGO,MAAM,yBAAA,GAA4B,CAAC,OAAA,KAA4B;AACpE,EAAA,IAAI,CAAC,SAAS,OAAO,CAAA;AAErB,EAAA,OAAO,uBAAuB,OAAO,CAAA;AACvC,CAAA;;ACAO,SAAS,oBAAA,CAAqB;AAAA,EACnC,SAAA;AAAA,EACA,KAAA;AAAA,EACA,QAAA;AAAA,EACA,UAAA;AAAA,EACA;AACF,CAAA,EAA8B;AAC5B,EAAA,MAAM;AAAA,IACJ,YAAA;AAAA,IACA,eAAA;AAAA,IACA,aAAA;AAAA,IACA,WAAA;AAAA,IACA,uBAAA;AAAA,IACA,sBAAA;AAAA,IACA,iBAAA;AAAA,IACA,iBAAA;AAAA,IACA;AAAA,MACE,mBAAA,EAAoB;AAExB,EAAA,MAAM,YAAA,GAAe,MAAM,MAAA,KAAW,CAAA;AAEtC,EAAA,MAAM,QAAQ,WAAA,GAAc,EAAA,GAAK,MAAM,aAAA,EAAe,SAAA,IAAa,aAAa,EAAE,CAAA;AAClF,EAAA,MAAM,IAAA,GAAO,8BAAcC,cAAA,CAAA,aAAA,CAAC,KAAA,EAAA,EAAI,WAAU,uBAAA,EAAA,EAAwB,eAAa,IAAS,aAAA,EAAe,WAAA;AAEvG,EAAA,MAAM,wBAAwB,WAAA,GAAc,CAAA,GAAI,gBAAA,CAAiB,aAAA,EAAe,aAAa,SAAS,CAAA;AAEtG,EAAA,MAAM,OAAA,GAAU,OAAuB,IAAI,CAAA;AAC3C,EAAA,MAAM,CAAC,oBAAA,EAAsB,uBAAuB,CAAA,GAAI,SAAS,CAAC,CAAA;AAClE,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,WAAA,IAAe,CAAC,aAAA,EAAe;AACjC,MAAA,uBAAA,CAAwB,CAAC,CAAA;AAEzB,MAAA;AAAA,IACF;AACA,IAAA,MAAM,KAAK,OAAA,CAAQ,OAAA;AACnB,IAAA,IAAI,CAAC,EAAA,EAAI;AACT,IAAA,MAAM,EAAA,GAAK,sBAAsB,MAAM;AACrC,MAAA,uBAAA,CAAwB,yBAAA,CAA0B,EAAE,CAAC,CAAA;AAAA,IACvD,CAAC,CAAA;AAED,IAAA,OAAO,MAAM,qBAAqB,EAAE,CAAA;AAAA,EACtC,CAAA,EAAG,CAAC,WAAA,EAAa,aAAa,CAAC,CAAA;AAE/B,EAAA,MAAM,wBAAwB,qBAAA,GAAwB,oBAAA;AAEtD,EAAA,MAAM,gBAAgB,KAAA,CAAM,MAAA;AAC5B,EAAA,MAAM,mBAAA,GAAsB,eACxB,IAAA,CAAK,GAAA;AAAA,IACH,CAAA;AAAA,IACA,MAAM,SAAA,CAAU,CAAC,MAAM,CAAA,CAAE,EAAA,KAAO,aAAa,EAAE;AAAA,GACjD,GACA,CAAA;AAEJ,EAAA,MAAM,aAAA,GAAgB,YAAY,MAAM;AACtC,IAAA,IAAI,mBAAA,GAAsB,gBAAgB,CAAA,EAAG;AAC3C,MAAA,eAAA,CAAgB,KAAA,CAAM,mBAAA,GAAsB,CAAC,CAAA,IAAK,IAAI,CAAA;AAAA,IACxD;AAAA,EACF,GAAG,CAAC,mBAAA,EAAqB,KAAA,EAAO,eAAA,EAAiB,aAAa,CAAC,CAAA;AAE/D,EAAA,MAAM,iBAAA,GAAoB,YAAY,MAAM;AAC1C,IAAA,IAAI,sBAAsB,CAAA,EAAG;AAC3B,MAAA,eAAA,CAAgB,KAAA,CAAM,mBAAA,GAAsB,CAAC,CAAA,IAAK,IAAI,CAAA;AAAA,IACxD;AAAA,EACF,CAAA,EAAG,CAAC,mBAAA,EAAqB,KAAA,EAAO,eAAe,CAAC,CAAA;AAEhD,EAAA,MAAM,gBAAA,GAAmB,cAAc,IAAA,IAAQ,UAAA;AAC/C,EAAA,MAAM,uBAAA,GAA0B,cAAc,WAAA,IAAe,iBAAA;AAE7D,EAAA,oDACG,IAAA,EAAA,EAAK,SAAA,EAAU,aAAY,WAAA,EAAU,mBAAA,EAAA,+CACnC,UAAA,EAAA,EAAW,SAAA,EAAU,+EACpBA,cAAA,CAAA,aAAA,CAAC,UAAA,EAAA,EAAW,WAAU,KAAA,EAAA,EACnB,CAAC,gCACAA,cAAA,CAAA,aAAA,CAAC,SAAA,EAAA,EAAU,WAAU,gDAAA,EAAA,kBACnBA,cAAA,CAAA,aAAA;AAAA,IAAC,iBAAA;AAAA,IAAA;AAAA,MACC,KAAA;AAAA,MACA,KAAA,EAAO,eAAe,KAAA,IAAS,KAAA;AAAA,MAC/B,gBAAA,EAAkB,qBAAA;AAAA,MAClB,UAAA,EAAY,gBAAA;AAAA,MACZ,iBAAA,EAAmB,uBAAA;AAAA,MACnB,mBAAA;AAAA,MACA,aAAA;AAAA,MACA,aAAA;AAAA,MACA,iBAAA;AAAA,MACA,sBAAA;AAAA,MACA,sBAAA,EAAwB,uBAAA;AAAA,MACxB,iBAAA;AAAA,MACA,iBAAA;AAAA,MACA;AAAA;AAAA,GAEJ,CAEJ,CAAA,kBACAA,cAAA,CAAA,aAAA,CAAC,eAAY,SAAA,EAAU,iCAAA,EAAA,+CAEpB,KAAA,EAAA,EAAI,aAAA,EAAY,QAAO,SAAA,EAAU,SAAA,EAAU,QAAM,IAAA,EAAA,EAC/C,QACH,GACC,YAAA,mBACCA,cAAA,CAAA,aAAA,CAAC,SAAI,SAAA,EAAU,uEAAA,EAAA,+CACZ,aAAA,EAAA,EAAc,SAAA,EAAU,yBAAwB,IAAA,EAAM,EAAA,EAAI,QAAO,MAAA,EAAO,CAAA,+CACxE,GAAA,EAAA,EAAE,SAAA,EAAU,2CAAwC,kCAAgC,CACvF,oBAEAA,cAAA,CAAA,aAAA,CAAC,KAAA,EAAA,EAAI,KAAK,OAAA,EAAA,EAAU,IAAK,CAE7B,CACF,CACF,CAAA;AAEJ;;AC3HA,MAAM,iBAAA,GAAoB,kCAAA;AAqB1B,MAAM,4BAA4BA,cAAA,CAAM,UAAA;AAAA,EACtC,SAASC,0BAAAA,CACP;AAAA,IACE,SAAA,GAAY,kBAAA;AAAA,IACZ,QAAA;AAAA,IACA,KAAA;AAAA,IACA,SAAA;AAAA,IACA,uBAAA;AAAA,IACA,sBAAA;AAAA,IACA,iBAAA;AAAA,IACA,iBAAA;AAAA,IACA,UAAA;AAAA,IACA,UAAA;AAAA,IACA,iBAAA;AAAA,IACA,GAAG;AAAA,KAEL,GAAA,EACA;AACA,IAAA,MAAM,QAAA,GAAW,OAAuB,IAAI,CAAA;AAC5C,IAAA,MAAM,EAAE,YAAA,EAAc,eAAA,EAAgB,GAAI,mBAAA,EAAoB;AAE9D,IAAA,mBAAA;AAAA,MACE,GAAA;AAAA,MACA,OAAO;AAAA,QACL,YAAA;AAAA,QACA;AAAA,OACF,CAAA;AAAA,MACA,CAAC,cAAc,eAAe;AAAA,KAChC;AAEA,IAAA,SAAA,CAAU,MAAM;AACd,MAAA,MAAM,SAAS,QAAA,CAAS,OAAA;AACxB,MAAA,IAAI,CAAC,MAAA,EAAQ;AAEb,MAAA,MAAM,eAAe,MAAM;AACzB,QAAA,MAAM,EAAE,MAAA,EAAO,GAAI,MAAA,CAAO,qBAAA,EAAsB;AAChD,QAAA,MAAA,CAAO,KAAA,CAAM,WAAA,CAAY,iBAAA,EAAmB,CAAA,EAAG,MAAM,CAAA,EAAA,CAAI,CAAA;AAAA,MAC3D,CAAA;AAEA,MAAA,YAAA,EAAa;AAEb,MAAA,IAAI,OAAO,mBAAmB,UAAA,EAAY;AACxC,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,QAAA,GAAW,IAAI,cAAA,CAAe,YAAY,CAAA;AAChD,MAAA,QAAA,CAAS,QAAQ,MAAM,CAAA;AAEvB,MAAA,OAAO,MAAM,SAAS,UAAA,EAAW;AAAA,IACnC,CAAA,EAAG,EAAE,CAAA;AAEL,IAAA,uBACED,cAAA,CAAA,aAAA,CAAC,IAAA,EAAA,EAAK,SAAA,EAAW,EAAA,CAAG,QAAA,EAAU,SAAS,CAAA,EAAA,kBACrCA,cAAA,CAAA,aAAA,CAAC,WAAA,EAAA,EAAY,SAAA,EAAU,mBAAA,EAAA,kBACrBA,cAAA,CAAA,aAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,GAAA,EAAK,QAAA;AAAA,QACL,SAAA,EAAU,yEAAA;AAAA,QACV,KAAA,EAAO,EAAE,CAAC,iBAAiB,GAAG,OAAA,EAAQ;AAAA,QACrC,GAAG;AAAA,OAAA;AAAA,mDAEH,UAAA,EAAA,EAAW,SAAA,EAAU,8FACpBA,cAAA,CAAA,aAAA,CAAC,UAAA,EAAA,EAAW,OAAc,CAC5B,CAAA;AAAA,sBACAA,cAAA,CAAA,aAAA;AAAA,QAAC,oBAAA;AAAA,QAAA;AAAA,UACC,SAAA;AAAA,UACA,KAAA;AAAA,UACA,UAAA;AAAA,UACA;AAAA,SAAA;AAAA,QAEC;AAAA;AACH,KAEJ,CACF,CAAA;AAAA,EAEJ;AACF,CAAA;AAEO,MAAM,uBAAuBA,cAAA,CAAM,UAAA;AAAA,EACxC,SAASE,qBAAAA,CAAqB,KAAA,EAAO,GAAA,EAAK;AACxC,IAAA,MAAM,EAAE,KAAA,EAAO,uBAAA,EAAyB,wBAAwB,iBAAA,EAAmB,iBAAA,EAAmB,YAAW,GAC/G,KAAA;AAEF,IAAA,uBACEF,cAAA,CAAA,aAAA;AAAA,MAAC,wBAAA;AAAA,MAAA;AAAA,QACC,qBAAqB,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,UAAU,CAAA,IAAK,IAAA;AAAA,QACxD,uBAAA;AAAA,QACA,sBAAA;AAAA,QACA,iBAAA;AAAA,QACA,iBAAA;AAAA,QACA;AAAA,OAAA;AAAA,sBAEAA,cAAA,CAAA,aAAA,CAAC,yBAAA,EAAA,EAA2B,GAAG,KAAA,EAAO,GAAA,EAAU;AAAA,KAClD;AAAA,EAEJ;AACF;;;;"}
|
|
1
|
+
{"version":3,"file":"knowledge-review.js","sources":["../../../src/scenes/knowledge-review/diff-loader.tsx","../../../src/scenes/knowledge-review/suggestions-header/suggestions-header.tsx","../../../src/lib/countSuggestions.ts","../../../src/scenes/knowledge-review/knowledge-review-panel.tsx","../../../src/scenes/knowledge-review/scene.tsx"],"sourcesContent":["import { useCallback, useEffect } from 'react';\n\nimport type { LoadedDiffDoc } from './context';\nimport { useReviewsSelection } from './context';\n\nexport type KnowledgeReviewDiffLoaderProps = {\n /** Called when selectedItem changes. Return diff payload or null. */\n fetchDiffForItem: (itemId: string) => Promise<LoadedDiffDoc | null>;\n};\n\n/**\n * Listens to selectedItem from context and fetches diff via the provided callback.\n * Owns loading state and context updates; host (Storybook or Platform) supplies fetch logic.\n */\nexport function KnowledgeReviewDiffLoader({ fetchDiffForItem }: KnowledgeReviewDiffLoaderProps) {\n const { selectedItem, setLoadedDiffDoc, setLoadingDiff } = useReviewsSelection();\n\n const loadDiffForItem = useCallback(\n async (itemId: string, signal: AbortSignal) => {\n setLoadingDiff(true);\n setLoadedDiffDoc(null);\n\n try {\n const doc = await fetchDiffForItem(itemId);\n if (signal.aborted) return;\n setLoadedDiffDoc(doc);\n } catch (error) {\n if (signal.aborted) return;\n console.error('Failed to fetch diff:', error);\n setLoadedDiffDoc(null);\n } finally {\n if (!signal.aborted) {\n setLoadingDiff(false);\n }\n }\n },\n [fetchDiffForItem, setLoadedDiffDoc, setLoadingDiff],\n );\n\n const selectedId = selectedItem?.id;\n\n useEffect(() => {\n if (!selectedId) {\n setLoadedDiffDoc(null);\n setLoadingDiff(false);\n\n return;\n }\n\n const abortController = new AbortController();\n void loadDiffForItem(selectedId, abortController.signal);\n\n return () => {\n abortController.abort();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedId, loadDiffForItem]);\n\n return null;\n}\n","import { CaretDown, CaretUp, Backspace, CheckCircle } from '@phosphor-icons/react';\nimport * as React from 'react';\n\nimport { EditCount } from '../review-list/edit-count';\n\nimport { Button } from '@/components/ui/button';\nimport { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';\nimport { ButtonGroup } from '@/components/ui/button-group';\nimport { cn } from '@/lib/utils';\nimport { dark } from '@/colors/dark';\nimport { StatusBadge } from '@/components/convos/status-badge';\n\nexport interface SuggestionsHeaderProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'title'> {\n title: React.ReactNode;\n isNew: boolean;\n suggestionsCount: number;\n sourceIcon: React.ReactNode;\n sourceDescription: string | null;\n currentArticleIndex: number;\n totalArticles: number;\n displayTotalArticles?: number;\n showActionButtons?: boolean;\n onNextArticle: () => void;\n onPreviousArticle: () => void;\n onRejectAllSuggestions: () => void;\n onAcceptAllSuggestions: () => void;\n breadcrumb?: string;\n onOpenArticleLink?: () => void;\n onSourceLinkClick?: () => void;\n}\n\nexport const SuggestionsHeader = React.forwardRef<HTMLDivElement, SuggestionsHeaderProps>(function SuggestionsHeader(\n {\n title,\n isNew,\n suggestionsCount,\n sourceIcon,\n sourceDescription,\n currentArticleIndex,\n totalArticles,\n displayTotalArticles,\n showActionButtons = true,\n onNextArticle,\n onPreviousArticle,\n onRejectAllSuggestions,\n onAcceptAllSuggestions,\n breadcrumb,\n onOpenArticleLink,\n onSourceLinkClick,\n className,\n ...props\n },\n ref,\n) {\n const hasNextArticle = totalArticles > 0 && currentArticleIndex < totalArticles - 1;\n const hasPreviousArticle = currentArticleIndex > 0;\n const currentArticle = totalArticles === 0 ? 0 : currentArticleIndex + 1;\n const totalArticlesForDisplay = displayTotalArticles ?? totalArticles;\n const hasDisplayArticles = totalArticlesForDisplay > 0;\n\n let status: React.ReactNode | undefined;\n if (isNew) {\n status = <StatusBadge variant=\"success\">New</StatusBadge>;\n } else if (suggestionsCount) {\n status = <EditCount count={suggestionsCount} />;\n }\n\n return (\n <div ref={ref} className={cn('flex flex-col gap-4', className)} {...props}>\n {/* Header + Navigation */}\n <div className=\"flex justify-between items-center\">\n <h1 className=\"heading-lg\">\n {title}\n {/* Breadcrumbs */}\n {onOpenArticleLink && breadcrumb && (\n <Button\n variant=\"link\"\n size=\"sm\"\n onClick={onOpenArticleLink}\n aria-label=\"Open article\"\n className=\"block px-0 text-subtle text-xs\"\n >\n {breadcrumb}\n </Button>\n )}\n </h1>\n {/* up/down carets */}\n <div className=\"flex items-center\">\n <p className=\"text-xs text-foreground\">\n <span aria-hidden=\"true\">{hasDisplayArticles ? `${currentArticle}/${totalArticlesForDisplay}` : '0'}</span>\n <span className=\"sr-only\" aria-live=\"polite\">\n {hasDisplayArticles ? `Article ${currentArticle} of ${totalArticlesForDisplay}` : 'No articles'}\n </span>\n </p>\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n disabled={!hasNextArticle}\n onClick={onNextArticle}\n aria-label=\"Go to next article\"\n >\n <CaretDown aria-hidden=\"true\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent side=\"bottom\" borderColor=\"transparent\" background={dark[900]} textColor={dark[100]}>\n Next Article\n </TooltipContent>\n </Tooltip>\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n disabled={!hasPreviousArticle}\n onClick={onPreviousArticle}\n aria-label=\"Go to previous article\"\n >\n <CaretUp aria-hidden=\"true\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent side=\"top\" borderColor=\"transparent\" background={dark[900]} textColor={dark[100]}>\n Previous Article\n </TooltipContent>\n </Tooltip>\n </div>\n </div>\n\n {/* Status, Source + Actions */}\n <div className=\"flex-1 px-2 pb-2 flex justify-between items-center\">\n <div className=\"flex items-center gap-2\">\n {status}\n {sourceDescription &&\n (onSourceLinkClick ? (\n <Button\n variant=\"link\"\n onClick={onSourceLinkClick}\n aria-label=\"Open source\"\n className=\"[&_svg]:size-4 text-xs text-subtle gap-1\"\n >\n {sourceIcon && <span className=\"shrink-0 flex items-center\">{sourceIcon}</span>}\n <span className=\"\">{sourceDescription}</span>\n </Button>\n ) : (\n <span className=\"text-xs text-subtle\">{sourceDescription}</span>\n ))}\n </div>\n {showActionButtons && (\n <ButtonGroup orientation=\"horizontal\" rounded={false} aria-label=\"Suggestion actions\" className=\"gap-1\">\n <Button variant=\"ghost\" onClick={onRejectAllSuggestions}>\n <Backspace aria-hidden=\"true\" />\n Reject\n </Button>\n <Button variant=\"shadow\" onClick={onAcceptAllSuggestions}>\n <CheckCircle aria-hidden=\"true\" />\n Accept as draft\n </Button>\n </ButtonGroup>\n )}\n </div>\n </div>\n );\n});\n","function countSuggestionsInRoot(root: Document | Element): number {\n const adjacentPairs = root.querySelectorAll('del + ins');\n const standaloneIns = root.querySelectorAll('ins:not(del + ins)');\n const allDel = root.querySelectorAll('del');\n const standaloneDel = Array.from(allDel).filter((del) => del.nextElementSibling?.tagName !== 'INS');\n\n return adjacentPairs.length + standaloneIns.length + standaloneDel.length;\n}\n\n/** Count suggestions in an HTML string (for title or raw HTML content). */\nexport const countSuggestions = (htmlString: string) => {\n if (!htmlString || typeof DOMParser === 'undefined') {\n return 0;\n }\n const parser = new DOMParser();\n const doc = parser.parseFromString(htmlString, 'text/html');\n\n return countSuggestionsInRoot(doc);\n};\n\n/** Count suggestions inside a DOM element (for rendered ReactNode body content). */\nexport const countSuggestionsInElement = (element: Element | null) => {\n if (!element) return 0;\n\n return countSuggestionsInRoot(element);\n};\n","import React, { useCallback, useEffect, useRef, useState } from 'react';\nimport parse from 'html-react-parser';\nimport { HandsClapping } from '@phosphor-icons/react';\n\nimport { useReviewsSelection } from './context';\nimport { SuggestionsHeader } from './suggestions-header';\nimport type { ReviewListItemProps } from './review-list';\n\nimport { countSuggestions, countSuggestionsInElement } from '@/lib/countSuggestions';\nimport { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';\nimport { ScrollArea } from '@/components/ui/scroll-area';\nimport { Spinner } from '@/components/ui/spinner';\n\nexport type KnowledgeReviewPanelProps = {\n diffTitle: string;\n items: ReviewListItemProps[];\n isLoading?: boolean;\n totalItemsCount?: number;\n showActionButtons?: boolean;\n children?: React.ReactNode;\n sourceIcon: React.ReactNode;\n sourceDescription: string | null;\n};\n\n/**\n * Panel that shows the selected diff (title + content), suggestion count, and article nav.\n * Must be used inside ReviewsSelectionProvider. Expects --knowledge-review-scroll-height\n * to be set by a parent for ScrollArea height.\n */\nexport function KnowledgeReviewPanel({\n diffTitle,\n items,\n isLoading,\n totalItemsCount,\n showActionButtons = true,\n children,\n sourceIcon,\n sourceDescription,\n}: KnowledgeReviewPanelProps) {\n const {\n selectedItem,\n setSelectedItem,\n loadedDiffDoc,\n loadingDiff,\n onApproveAllSuggestions,\n onRejectAllSuggestions,\n onOpenArticleLink,\n onSourceLinkClick,\n breadcrumb,\n } = useReviewsSelection();\n\n const hasItems = items.length > 0;\n const resolvedIsLoading = isLoading ?? !hasItems;\n const isLoadingState = resolvedIsLoading && !hasItems;\n const isEmptyState = !resolvedIsLoading && !hasItems;\n\n const title = loadingDiff ? '' : parse(loadedDiffDoc?.diffTitle ?? diffTitle ?? '');\n const body = loadingDiff ? <div className=\"text-muted-foreground\">Loading diff…</div> : loadedDiffDoc?.diffContent;\n\n const titleSuggestionsCount = loadingDiff ? 0 : countSuggestions(loadedDiffDoc?.diffTitle ?? diffTitle);\n\n const bodyRef = useRef<HTMLDivElement>(null);\n const [bodySuggestionsCount, setBodySuggestionsCount] = useState(0);\n useEffect(() => {\n if (loadingDiff || !loadedDiffDoc) {\n setBodySuggestionsCount(0);\n\n return;\n }\n const el = bodyRef.current;\n if (!el) return;\n const id = requestAnimationFrame(() => {\n setBodySuggestionsCount(countSuggestionsInElement(el));\n });\n\n return () => cancelAnimationFrame(id);\n }, [loadingDiff, loadedDiffDoc]);\n\n const suggestionsCount = titleSuggestionsCount + bodySuggestionsCount;\n\n const totalArticles = items.length;\n const totalArticlesForDisplay = totalItemsCount ?? totalArticles;\n const currentArticleIndex = selectedItem\n ? Math.max(\n 0,\n items.findIndex((i) => i.id === selectedItem.id),\n )\n : 0;\n\n const onNextArticle = useCallback(() => {\n if (currentArticleIndex < totalArticles - 1) {\n setSelectedItem(items[currentArticleIndex + 1] ?? null);\n }\n }, [currentArticleIndex, items, setSelectedItem, totalArticles]);\n\n const onPreviousArticle = useCallback(() => {\n if (currentArticleIndex > 0) {\n setSelectedItem(items[currentArticleIndex - 1] ?? null);\n }\n }, [currentArticleIndex, items, setSelectedItem]);\n\n const headerSourceIcon = selectedItem?.icon ?? sourceIcon;\n const headerSourceDescription = selectedItem?.description ?? sourceDescription;\n\n return (\n <Card className=\"py-6 pl-4\" data-name=\"knowledge-reviews\">\n <ScrollArea className=\"h-[calc(var(--knowledge-review-scroll-height)-50px)] pr-8\">\n <CardHeader className=\"p-0\">\n {hasItems && (\n <CardTitle className=\"border-b border-dark-300 mb-6 pb-2 font-normal\">\n <SuggestionsHeader\n title={title}\n isNew={loadedDiffDoc?.isNew ?? false}\n suggestionsCount={suggestionsCount}\n sourceIcon={headerSourceIcon}\n sourceDescription={headerSourceDescription}\n currentArticleIndex={currentArticleIndex}\n totalArticles={totalArticles}\n displayTotalArticles={totalArticlesForDisplay}\n showActionButtons={showActionButtons}\n onNextArticle={onNextArticle}\n onPreviousArticle={onPreviousArticle}\n onRejectAllSuggestions={onRejectAllSuggestions}\n onAcceptAllSuggestions={onApproveAllSuggestions}\n onOpenArticleLink={onOpenArticleLink}\n onSourceLinkClick={onSourceLinkClick}\n breadcrumb={breadcrumb}\n />\n </CardTitle>\n )}\n </CardHeader>\n <CardContent className=\"p-0 [&_ol]:!pl-16 [&_ul]:!pl-16\">\n {/* Mount point for children (e.g. KnowledgeReviewDiffLoader). Kept in DOM so its effects run; hidden because it has no UI. */}\n <div aria-hidden=\"true\" className=\"sr-only\" hidden>\n {children}\n </div>\n {isLoadingState ? (\n <div className=\"flex flex-col items-center justify-center gap-4 text-center h-[50dvh] text-muted-foreground\">\n <Spinner className=\"size-8\" />\n <p className=\"text-base font-medium\">Loading suggestions...</p>\n </div>\n ) : isEmptyState ? (\n <div className=\"flex flex-col items-center justify-center gap-4 text-center h-[50dvh]\">\n <HandsClapping className=\"text-muted-foreground\" size={32} weight=\"fill\" />\n <p className=\"text-base font-medium text-foreground\">All up to date. Well done, mate.</p>\n </div>\n ) : (\n <div ref={bodyRef}>{body}</div>\n )}\n </CardContent>\n </ScrollArea>\n </Card>\n );\n}\n","import React, { useEffect, useImperativeHandle, useRef } from 'react';\n\nimport { useReviewsSelection } from './context';\nimport { ReviewList, ReviewListItemProps, ReviewsSelectionProvider } from './review-list';\nimport { KnowledgeReviewPanel } from './knowledge-review-panel';\n\nimport { Card, CardContent } from '@/components/ui/card';\nimport { ScrollArea } from '@/components/ui/scroll-area';\nimport { Spinner } from '@/components/ui/spinner';\nimport { cn } from '@/lib/utils';\n\nimport './knowledge-review.css';\n\nconst SCROLL_HEIGHT_VAR = '--knowledge-review-scroll-height';\n\nexport type KnowledgeReviewSceneHandle = {\n selectedItem: ReviewListItemProps | null;\n setSelectedItem: (item: ReviewListItemProps | null) => void;\n};\n\nexport type KnowledgeReviewSceneProps = {\n diffTitle?: string;\n children: React.ReactNode;\n items: ReviewListItemProps[];\n isLoading?: boolean;\n /** Total number of review list items available (can exceed currently loaded `items.length`). */\n totalItemsCount?: number;\n /** Controls visibility of the Reject / Accept action buttons in the review header. */\n showActionButtons?: boolean;\n className?: string;\n onApproveAllSuggestions: () => void;\n onRejectAllSuggestions: () => void;\n onOpenArticleLink?: () => void;\n onSourceLinkClick?: () => void;\n breadcrumb?: string;\n sourceIcon: React.ReactNode;\n sourceDescription: string | null;\n};\n\nconst KnowledgeReviewSceneInner = React.forwardRef<KnowledgeReviewSceneHandle, KnowledgeReviewSceneProps>(\n function KnowledgeReviewSceneInner(\n {\n diffTitle = 'Knowledge Review',\n children,\n items,\n isLoading,\n totalItemsCount,\n showActionButtons = true,\n className,\n onApproveAllSuggestions,\n onRejectAllSuggestions,\n onOpenArticleLink,\n onSourceLinkClick,\n breadcrumb,\n sourceIcon,\n sourceDescription,\n ...props\n },\n ref,\n ) {\n const innerRef = useRef<HTMLDivElement>(null);\n const { selectedItem, setSelectedItem } = useReviewsSelection();\n\n useImperativeHandle(\n ref,\n () => ({\n selectedItem,\n setSelectedItem,\n }),\n [selectedItem, setSelectedItem],\n );\n\n useEffect(() => {\n const cardEl = innerRef.current;\n if (!cardEl) return;\n\n const updateHeight = () => {\n const { height } = cardEl.getBoundingClientRect();\n cardEl.style.setProperty(SCROLL_HEIGHT_VAR, `${height}px`);\n };\n\n updateHeight();\n\n if (typeof ResizeObserver !== 'function') {\n return;\n }\n\n const observer = new ResizeObserver(updateHeight);\n observer.observe(cardEl);\n\n return () => observer.disconnect();\n }, []);\n\n const resolvedIsLoading = isLoading ?? items.length === 0;\n const isLoadingItems = resolvedIsLoading && items.length === 0;\n\n return (\n <Card className={cn('h-full', className)}>\n <CardContent className=\"p-4 lg:p-8 h-full\">\n <div\n ref={innerRef}\n className=\"grid xs:max-lg:grid-cols-1 lg:grid-cols-[1fr_4fr] gap-6 min-h-96 h-full\"\n style={{ [SCROLL_HEIGHT_VAR]: '100px' } as React.CSSProperties}\n {...props}\n >\n <ScrollArea className=\"h-[calc(var(--knowledge-review-scroll-height))] min-w-80 lg:block hidden\">\n {isLoadingItems ? (\n <div className=\"flex h-full min-h-96 items-center justify-center text-muted-foreground\">\n <Spinner className=\"size-6\" />\n </div>\n ) : (\n <ReviewList items={items} />\n )}\n </ScrollArea>\n <KnowledgeReviewPanel\n diffTitle={diffTitle}\n items={items}\n isLoading={resolvedIsLoading}\n totalItemsCount={totalItemsCount}\n showActionButtons={showActionButtons}\n sourceIcon={sourceIcon}\n sourceDescription={sourceDescription}\n >\n {children}\n </KnowledgeReviewPanel>\n </div>\n </CardContent>\n </Card>\n );\n },\n);\n\nexport const KnowledgeReviewScene = React.forwardRef<KnowledgeReviewSceneHandle, KnowledgeReviewSceneProps>(\n function KnowledgeReviewScene(props, ref) {\n const { items, onApproveAllSuggestions, onRejectAllSuggestions, onOpenArticleLink, onSourceLinkClick, breadcrumb } =\n props;\n\n return (\n <ReviewsSelectionProvider\n defaultSelectedItem={items.find((m) => m.isSelected) ?? null}\n onApproveAllSuggestions={onApproveAllSuggestions}\n onRejectAllSuggestions={onRejectAllSuggestions}\n onOpenArticleLink={onOpenArticleLink}\n onSourceLinkClick={onSourceLinkClick}\n breadcrumb={breadcrumb}\n >\n <KnowledgeReviewSceneInner {...props} ref={ref} />\n </ReviewsSelectionProvider>\n );\n },\n);\n"],"names":["SuggestionsHeader","React","KnowledgeReviewSceneInner","KnowledgeReviewScene"],"mappings":"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"}
|
|
@@ -17,11 +17,14 @@ export declare type KnowledgeReviewDiffLoaderProps = {
|
|
|
17
17
|
* Must be used inside ReviewsSelectionProvider. Expects --knowledge-review-scroll-height
|
|
18
18
|
* to be set by a parent for ScrollArea height.
|
|
19
19
|
*/
|
|
20
|
-
export declare function KnowledgeReviewPanel({ diffTitle, items, children, sourceIcon, sourceDescription, }: KnowledgeReviewPanelProps): default_2.JSX.Element;
|
|
20
|
+
export declare function KnowledgeReviewPanel({ diffTitle, items, isLoading, totalItemsCount, showActionButtons, children, sourceIcon, sourceDescription, }: KnowledgeReviewPanelProps): default_2.JSX.Element;
|
|
21
21
|
|
|
22
22
|
export declare type KnowledgeReviewPanelProps = {
|
|
23
23
|
diffTitle: string;
|
|
24
24
|
items: ReviewListItemProps[];
|
|
25
|
+
isLoading?: boolean;
|
|
26
|
+
totalItemsCount?: number;
|
|
27
|
+
showActionButtons?: boolean;
|
|
25
28
|
children?: default_2.ReactNode;
|
|
26
29
|
sourceIcon: default_2.ReactNode;
|
|
27
30
|
sourceDescription: string | null;
|
|
@@ -38,6 +41,11 @@ export declare type KnowledgeReviewSceneProps = {
|
|
|
38
41
|
diffTitle?: string;
|
|
39
42
|
children: default_2.ReactNode;
|
|
40
43
|
items: ReviewListItemProps[];
|
|
44
|
+
isLoading?: boolean;
|
|
45
|
+
/** Total number of review list items available (can exceed currently loaded `items.length`). */
|
|
46
|
+
totalItemsCount?: number;
|
|
47
|
+
/** Controls visibility of the Reject / Accept action buttons in the review header. */
|
|
48
|
+
showActionButtons?: boolean;
|
|
41
49
|
className?: string;
|
|
42
50
|
onApproveAllSuggestions: () => void;
|
|
43
51
|
onRejectAllSuggestions: () => void;
|