@c-rex/components 0.1.33 → 0.1.36
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/package.json +1 -1
- package/src/autocomplete.tsx +60 -37
- package/src/favorites/bookmark-button.analysis.md +7 -5
- package/src/favorites/bookmark-button.tsx +37 -39
- package/src/favorites/favorite-button.analysis.md +4 -3
- package/src/favorites/favorite-button.tsx +7 -30
- package/src/results/pagination.tsx +18 -8
- package/src/search-input.tsx +1 -1
- package/src/stores/favorites-store.ts +21 -21
- /package/src/results/{cards.analysis.md → analysis/cards.analysis.md} +0 -0
- /package/src/results/{dialog-filter.analysis.md → analysis/dialog-filter.analysis.md} +0 -0
- /package/src/results/{empty.analysis.md → analysis/empty.analysis.md} +0 -0
- /package/src/results/{filter-navbar.analysis.md → analysis/filter-navbar.analysis.md} +0 -0
- /package/src/results/{pagination.analysis.md → analysis/pagination.analysis.md} +0 -0
- /package/src/results/{table-with-images.analysis.md → analysis/table-with-images.analysis.md} +0 -0
- /package/src/results/{table.analysis.md → analysis/table.analysis.md} +0 -0
package/package.json
CHANGED
package/src/autocomplete.tsx
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
3
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
4
|
-
import {
|
|
4
|
+
import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput } from "@c-rex/ui/input-group";
|
|
5
5
|
import { useTranslations } from "next-intl";
|
|
6
6
|
import { SuggestionQueryParams } from "@c-rex/interfaces";
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
import { useRouter } from 'next/navigation';
|
|
7
|
+
import { X } from "lucide-react";
|
|
8
|
+
import { useRouter, useSearchParams } from "next/navigation";
|
|
10
9
|
import { suggestionRequest } from "./generated/create-suggestions-request";
|
|
11
10
|
import { useQueryState } from "nuqs";
|
|
12
11
|
|
|
@@ -18,11 +17,13 @@ export type AutoCompleteProps = {
|
|
|
18
17
|
onSelectParams?: { key: string, value: string }[];
|
|
19
18
|
onSelectPath: string
|
|
20
19
|
inputClass?: string
|
|
20
|
+
keepParams?: boolean;
|
|
21
21
|
};
|
|
22
22
|
|
|
23
23
|
export const AutoComplete = ({
|
|
24
24
|
initialValue = "",
|
|
25
25
|
embedded = true,
|
|
26
|
+
keepParams = false,
|
|
26
27
|
endpoint,
|
|
27
28
|
queryParams,
|
|
28
29
|
onSelectParams,
|
|
@@ -33,6 +34,7 @@ export const AutoComplete = ({
|
|
|
33
34
|
const [pkg] = useQueryState("package");
|
|
34
35
|
|
|
35
36
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
37
|
+
const searchParams = useSearchParams();
|
|
36
38
|
const router = useRouter();
|
|
37
39
|
const [open, setOpen] = useState(false);
|
|
38
40
|
const [query, setQuery] = useState(initialValue);
|
|
@@ -46,30 +48,33 @@ export const AutoComplete = ({
|
|
|
46
48
|
const results = await suggestionRequest({ endpoint, prefix, queryParams: params });
|
|
47
49
|
|
|
48
50
|
return results.data;
|
|
49
|
-
}, [endpoint, queryParams]);
|
|
51
|
+
}, [endpoint, pkg, queryParams]);
|
|
50
52
|
|
|
51
53
|
const handleSelect = (value: string) => {
|
|
52
54
|
setQuery(value);
|
|
53
55
|
setOpen(false);
|
|
54
|
-
|
|
55
|
-
|
|
56
|
+
const nextParams = new URLSearchParams(keepParams ? searchParams.toString() : "");
|
|
57
|
+
nextParams.set("page", "1");
|
|
58
|
+
nextParams.set("search", value);
|
|
59
|
+
onSelectParams?.forEach(param => {
|
|
60
|
+
nextParams.set(param.key, param.value);
|
|
61
|
+
});
|
|
56
62
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const searchSettings = useSearchSettingsStore.getState();
|
|
63
|
+
router.push(`${onSelectPath}?${nextParams.toString()}`);
|
|
64
|
+
};
|
|
60
65
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
66
|
+
const clearSearch = () => {
|
|
67
|
+
setQuery("");
|
|
68
|
+
setOpen(false);
|
|
69
|
+
const nextParams = new URLSearchParams(keepParams ? searchParams.toString() : "");
|
|
70
|
+
nextParams.set("page", "1");
|
|
71
|
+
nextParams.delete("search");
|
|
72
|
+
const queryString = nextParams.toString();
|
|
67
73
|
|
|
68
74
|
onSelectParams?.forEach(param => {
|
|
69
|
-
|
|
75
|
+
nextParams.set(param.key, param.value);
|
|
70
76
|
});
|
|
71
|
-
|
|
72
|
-
router.push(`${onSelectPath}?${params.toString()}`);
|
|
77
|
+
router.push(queryString ? `${onSelectPath}?${queryString}` : onSelectPath);
|
|
73
78
|
};
|
|
74
79
|
|
|
75
80
|
useEffect(() => {
|
|
@@ -105,23 +110,37 @@ export const AutoComplete = ({
|
|
|
105
110
|
|
|
106
111
|
return (
|
|
107
112
|
<div className="relative flex-1" ref={containerRef}>
|
|
108
|
-
<
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
e.
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
113
|
+
<InputGroup variant={embedded ? "embedded" : "default"}>
|
|
114
|
+
<InputGroupInput
|
|
115
|
+
variant={embedded ? "embedded" : undefined}
|
|
116
|
+
className={inputClass}
|
|
117
|
+
type="text"
|
|
118
|
+
placeholder={t("search")}
|
|
119
|
+
value={query}
|
|
120
|
+
onChange={(e) => {
|
|
121
|
+
setQuery(e.target.value);
|
|
122
|
+
setOpen(true);
|
|
123
|
+
}}
|
|
124
|
+
onKeyDown={(e) => {
|
|
125
|
+
if (e.key === "Enter") {
|
|
126
|
+
e.preventDefault();
|
|
127
|
+
handleSelect(query);
|
|
128
|
+
}
|
|
129
|
+
}}
|
|
130
|
+
/>
|
|
131
|
+
{query.length > 0 && (
|
|
132
|
+
<InputGroupAddon align="inline-end">
|
|
133
|
+
<InputGroupButton
|
|
134
|
+
size="icon-xs"
|
|
135
|
+
variant="ghost"
|
|
136
|
+
aria-label="Clear search"
|
|
137
|
+
onClick={clearSearch}
|
|
138
|
+
>
|
|
139
|
+
<X className="size-3" />
|
|
140
|
+
</InputGroupButton>
|
|
141
|
+
</InputGroupAddon>
|
|
142
|
+
)}
|
|
143
|
+
</InputGroup>
|
|
125
144
|
|
|
126
145
|
{open && (
|
|
127
146
|
<ul className="suggestions-list absolute z-10 w-full bg-white border border-gray-300 rounded-lg shadow-lg max-h-60 overflow-y-auto">
|
|
@@ -139,7 +158,11 @@ export const AutoComplete = ({
|
|
|
139
158
|
<li
|
|
140
159
|
key={option}
|
|
141
160
|
className="px-4 py-2 hover:bg-accent cursor-pointer text-sm"
|
|
142
|
-
onClick={() =>
|
|
161
|
+
onClick={() => {
|
|
162
|
+
//handleSelect(`"${option}"`)
|
|
163
|
+
// TODO: check if the quotes are necessary
|
|
164
|
+
handleSelect(option)
|
|
165
|
+
}}
|
|
143
166
|
>
|
|
144
167
|
{option}
|
|
145
168
|
</li>
|
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
- Component: packages/components/src/favorites/bookmark-button.tsx
|
|
4
4
|
- Type: Client component
|
|
5
|
-
- Detected signals: useQueryStates=no, stores=
|
|
5
|
+
- Detected signals: useQueryStates=no, stores=no, window/document=yes, effects=yes, fetch/call=no
|
|
6
6
|
|
|
7
7
|
## Possible re-render causes
|
|
8
|
-
-
|
|
8
|
+
- Effects that update state can add extra renders on mount and dependency changes.
|
|
9
9
|
|
|
10
10
|
## Possible bugs/risks
|
|
11
|
-
-
|
|
11
|
+
- Access to window/document needs care to avoid hydration mismatch and non-browser runtime issues.
|
|
12
|
+
- markersList is loaded only on mount/shortId change; later store updates may not refresh the badge.
|
|
12
13
|
|
|
13
14
|
## Recommended improvements
|
|
14
|
-
- Keep
|
|
15
|
-
-
|
|
15
|
+
- Keep browser-only access inside event handlers or useEffect, not in initial render paths.
|
|
16
|
+
- Read documents[shortId]?.topics directly through a Zustand selector to keep UI reactive.
|
|
17
|
+
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { ComponentProps, FC, useState } from "react";
|
|
4
|
-
import { Button } from "@c-rex/ui/button";
|
|
3
|
+
import { ComponentProps, FC, ReactNode, useEffect, useState } from "react";
|
|
4
|
+
import { Button, ButtonProps } from "@c-rex/ui/button";
|
|
5
5
|
import { Trash } from "lucide-react";
|
|
6
6
|
import { cn } from "@c-rex/utils";
|
|
7
7
|
import Link from "next/link";
|
|
@@ -20,18 +20,17 @@ type BookmarkProps = {
|
|
|
20
20
|
triggerVariant?: ComponentProps<typeof Button>["variant"];
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
const EMPTY_TOPICS: Array<{ id: string; label: string; color: string }> = [];
|
|
24
|
-
|
|
25
23
|
export const BookmarkButton: FC<BookmarkProps> = ({
|
|
26
24
|
shortId,
|
|
27
25
|
triggerVariant = "outline"
|
|
28
26
|
}) => {
|
|
29
|
-
const [
|
|
30
|
-
const document = useFavoritesStore((state) => state.documents[shortId]);
|
|
31
|
-
const markersList = document?.topics ?? EMPTY_TOPICS;
|
|
27
|
+
const [markersList, setMarkersList] = useState<Array<{ id: string; label: string; color: string }>>([]);
|
|
32
28
|
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
setMarkersList(useFavoritesStore.getState().documents[shortId]?.topics || []);
|
|
31
|
+
}, [shortId]);
|
|
33
32
|
return (
|
|
34
|
-
<Dialog
|
|
33
|
+
<Dialog>
|
|
35
34
|
<DialogTrigger asChild>
|
|
36
35
|
<Button variant={triggerVariant} size="icon" className="relative">
|
|
37
36
|
<FaRegBookmark className="text-primary" />
|
|
@@ -44,38 +43,37 @@ export const BookmarkButton: FC<BookmarkProps> = ({
|
|
|
44
43
|
</span>
|
|
45
44
|
)}
|
|
46
45
|
</Button>
|
|
46
|
+
|
|
47
47
|
</DialogTrigger>
|
|
48
|
-
|
|
49
|
-
<
|
|
50
|
-
<
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
<
|
|
57
|
-
|
|
58
|
-
{
|
|
59
|
-
<
|
|
60
|
-
<
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
<
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
<
|
|
69
|
-
<
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
</DialogContent>
|
|
78
|
-
)}
|
|
48
|
+
<DialogContent>
|
|
49
|
+
<DialogHeader>
|
|
50
|
+
<DialogTitle>Bookmarks</DialogTitle>
|
|
51
|
+
<DialogDescription>
|
|
52
|
+
Manage your bookmarks here
|
|
53
|
+
</DialogDescription>
|
|
54
|
+
</DialogHeader>
|
|
55
|
+
<Table>
|
|
56
|
+
<TableBody>
|
|
57
|
+
{markersList.map((item) => (
|
|
58
|
+
<TableRow key={item.id} className="min-h-12">
|
|
59
|
+
<TableCell>
|
|
60
|
+
<FaRegBookmark className={cn("w-5", `text-${item.color}`)} />
|
|
61
|
+
</TableCell>
|
|
62
|
+
<TableCell>
|
|
63
|
+
<Link href={`${window.location.origin}/topics/${item.id}`}>
|
|
64
|
+
{item.label}
|
|
65
|
+
</Link>
|
|
66
|
+
</TableCell>
|
|
67
|
+
<TableCell>
|
|
68
|
+
<Button variant="destructive" size="icon">
|
|
69
|
+
<Trash className="w-5 hover:text-red-600 cursor-pointer" />
|
|
70
|
+
</Button>
|
|
71
|
+
</TableCell>
|
|
72
|
+
</TableRow>
|
|
73
|
+
))}
|
|
74
|
+
</TableBody>
|
|
75
|
+
</Table>
|
|
76
|
+
</DialogContent>
|
|
79
77
|
</Dialog>
|
|
80
78
|
)
|
|
81
79
|
}
|
|
@@ -10,8 +10,9 @@
|
|
|
10
10
|
|
|
11
11
|
## Possible bugs/risks
|
|
12
12
|
- Async flows can hit race conditions during fast param/route changes.
|
|
13
|
-
-
|
|
13
|
+
- useEffect with empty deps calls getTopicDocumentData(id) and does not react if id/type changes.
|
|
14
14
|
|
|
15
15
|
## Recommended improvements
|
|
16
|
-
-
|
|
17
|
-
-
|
|
16
|
+
- Consider cancellation guards (isMounted or AbortController) and standardized error handling.
|
|
17
|
+
- Include id and type in effect dependencies and handle fetch cancellation on unmount.
|
|
18
|
+
|
|
@@ -19,32 +19,10 @@ export const FavoriteButton: FC<{ id: string, type: ResultTypes, label: string }
|
|
|
19
19
|
const [documentData, setDocumentData] = useState<{ id: string, label: string }>({ id, label });
|
|
20
20
|
|
|
21
21
|
useEffect(() => {
|
|
22
|
-
if (type
|
|
23
|
-
|
|
24
|
-
return;
|
|
22
|
+
if (type === RESULT_TYPES.TOPIC) {
|
|
23
|
+
getTopicDocumentData(id);
|
|
25
24
|
}
|
|
26
|
-
|
|
27
|
-
let isCancelled = false;
|
|
28
|
-
const controller = new AbortController();
|
|
29
|
-
|
|
30
|
-
const loadTopicDocumentData = async () => {
|
|
31
|
-
try {
|
|
32
|
-
const data = await getTopicDocumentData(id, controller.signal);
|
|
33
|
-
if (!isCancelled) {
|
|
34
|
-
setDocumentData(data);
|
|
35
|
-
}
|
|
36
|
-
} catch (error) {
|
|
37
|
-
if ((error as Error).name === "AbortError") return;
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
loadTopicDocumentData();
|
|
42
|
-
|
|
43
|
-
return () => {
|
|
44
|
-
isCancelled = true;
|
|
45
|
-
controller.abort();
|
|
46
|
-
};
|
|
47
|
-
}, [id, label, type]);
|
|
25
|
+
}, []);
|
|
48
26
|
|
|
49
27
|
const addFavorite = async (id: string) => {
|
|
50
28
|
if (type === RESULT_TYPES.DOCUMENT) {
|
|
@@ -67,18 +45,17 @@ export const FavoriteButton: FC<{ id: string, type: ResultTypes, label: string }
|
|
|
67
45
|
removeFavoriteTopic(documentData.id, id);
|
|
68
46
|
}
|
|
69
47
|
|
|
70
|
-
const getTopicDocumentData = async (topicId: string
|
|
48
|
+
const getTopicDocumentData = async (topicId: string): Promise<void> => {
|
|
71
49
|
|
|
72
50
|
const response = await fetch(`/api/information-units/document-by-topic-id?shortId=${topicId}`, {
|
|
73
|
-
method: "GET"
|
|
74
|
-
signal,
|
|
51
|
+
method: "GET"
|
|
75
52
|
});
|
|
76
53
|
|
|
77
54
|
if (!response.ok) throw new Error("Failed to fetch document by topic id")
|
|
78
55
|
|
|
79
|
-
const { documentId, label
|
|
56
|
+
const { documentId, label } = await response.json();
|
|
80
57
|
|
|
81
|
-
|
|
58
|
+
setDocumentData({ id: documentId, label });
|
|
82
59
|
}
|
|
83
60
|
|
|
84
61
|
if (isFavorite) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
|
-
import { FC } from "react";
|
|
3
|
+
import { FC, MouseEvent } from "react";
|
|
4
4
|
import {
|
|
5
5
|
Pagination as PaginationUI,
|
|
6
6
|
PaginationContent,
|
|
@@ -19,15 +19,25 @@ interface PaginationProps {
|
|
|
19
19
|
export const Pagination: FC<PaginationProps> = ({ pageInfo }) => {
|
|
20
20
|
const disabledClass = "opacity-50 pointer-events-none";
|
|
21
21
|
|
|
22
|
-
const [
|
|
22
|
+
const [, setPage] = useQueryState('page',
|
|
23
23
|
parseAsInteger.withOptions({
|
|
24
24
|
history: 'push',
|
|
25
25
|
shallow: false,
|
|
26
26
|
})
|
|
27
27
|
)
|
|
28
28
|
|
|
29
|
-
const onChangePage = (pageNumber: number) => {
|
|
30
|
-
|
|
29
|
+
const onChangePage = (event: MouseEvent<HTMLAnchorElement>, pageNumber: number) => {
|
|
30
|
+
event.preventDefault();
|
|
31
|
+
|
|
32
|
+
if (
|
|
33
|
+
pageNumber < 1
|
|
34
|
+
|| (pageInfo.pageCount !== undefined && pageNumber > pageInfo.pageCount)
|
|
35
|
+
|| pageNumber === pageInfo.pageNumber
|
|
36
|
+
) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
void setPage(pageNumber);
|
|
31
41
|
}
|
|
32
42
|
|
|
33
43
|
return (
|
|
@@ -37,7 +47,7 @@ export const Pagination: FC<PaginationProps> = ({ pageInfo }) => {
|
|
|
37
47
|
<PaginationPrevious
|
|
38
48
|
href="#"
|
|
39
49
|
className={pageInfo.pageNumber === 1 ? disabledClass : ""}
|
|
40
|
-
onClick={() => onChangePage(pageInfo.pageNumber! - 1)}
|
|
50
|
+
onClick={(event) => onChangePage(event, pageInfo.pageNumber! - 1)}
|
|
41
51
|
/>
|
|
42
52
|
</PaginationItem>
|
|
43
53
|
|
|
@@ -46,7 +56,7 @@ export const Pagination: FC<PaginationProps> = ({ pageInfo }) => {
|
|
|
46
56
|
<PaginationLink
|
|
47
57
|
href="#"
|
|
48
58
|
isActive={page === pageInfo.pageNumber}
|
|
49
|
-
onClick={() => onChangePage(page)}
|
|
59
|
+
onClick={(event) => onChangePage(event, page)}
|
|
50
60
|
>
|
|
51
61
|
{page}
|
|
52
62
|
</PaginationLink>
|
|
@@ -61,11 +71,11 @@ export const Pagination: FC<PaginationProps> = ({ pageInfo }) => {
|
|
|
61
71
|
<PaginationItem>
|
|
62
72
|
<PaginationNext
|
|
63
73
|
href="#"
|
|
64
|
-
onClick={() => onChangePage(pageInfo.pageNumber! + 1)}
|
|
74
|
+
onClick={(event) => onChangePage(event, pageInfo.pageNumber! + 1)}
|
|
65
75
|
className={pageInfo.pageNumber === pageInfo.pageCount ? disabledClass : ""}
|
|
66
76
|
/>
|
|
67
77
|
</PaginationItem>
|
|
68
78
|
</PaginationContent>
|
|
69
79
|
</PaginationUI>
|
|
70
80
|
)
|
|
71
|
-
}
|
|
81
|
+
}
|
package/src/search-input.tsx
CHANGED
|
@@ -44,7 +44,7 @@ export const SearchInput: FC<Props> = ({
|
|
|
44
44
|
<>
|
|
45
45
|
<Search className="shrink-0 opacity-50" />
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
|
|
48
48
|
<AutocompleteComponent
|
|
49
49
|
onSelectParams={
|
|
50
50
|
(pkg && checked && showPkgFilter) ? [{ key: "packages", value: pkg }] : []
|
|
@@ -60,29 +60,29 @@ export const useFavoritesStore = create<FavoritesStore>()(
|
|
|
60
60
|
|
|
61
61
|
|
|
62
62
|
const favoriteTopic = (documents: Record<string, { topics: Favorite[] }>, documentId: string, id: string, label: string, color: string): Record<string, { topics: Favorite[] }> => {
|
|
63
|
-
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
[documentId]:
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
63
|
+
|
|
64
|
+
const documentsCopy = { ...documents };
|
|
65
|
+
const notFound = documents[documentId] == undefined;
|
|
66
|
+
|
|
67
|
+
if (notFound) {
|
|
68
|
+
documentsCopy[documentId] = { topics: [] };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
documentsCopy[documentId]!.topics.push({ id, label, color });
|
|
72
|
+
|
|
73
|
+
return documentsCopy
|
|
73
74
|
};
|
|
74
75
|
|
|
75
76
|
const unfavoriteTopic = (documents: Record<string, { topics: Favorite[] }>, documentId: string, id: string): Record<string, { topics: Favorite[] }> => {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
77
|
+
|
|
78
|
+
const documentsCopy = { ...documents };
|
|
79
|
+
const notFound = documents[documentId] == undefined;
|
|
80
|
+
|
|
81
|
+
if (notFound) {
|
|
82
|
+
return documentsCopy;
|
|
79
83
|
}
|
|
80
84
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
topics: currentDocument.topics.filter((topic) => topic.id !== id),
|
|
86
|
-
},
|
|
87
|
-
};
|
|
88
|
-
}
|
|
85
|
+
documentsCopy[documentId]!.topics = documentsCopy[documentId]!.topics.filter(topic => topic.id !== id);
|
|
86
|
+
|
|
87
|
+
return documentsCopy
|
|
88
|
+
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/src/results/{table-with-images.analysis.md → analysis/table-with-images.analysis.md}
RENAMED
|
File without changes
|
|
File without changes
|