Skip to content

Commit 40cbff3

Browse files
Merge pull request #184 from SE-UUlm/feat/42-use-case-view-paper-references-and-citations
Add paper references and citations to paper view
2 parents 102e26a + 29d73e9 commit 40cbff3

21 files changed

+478
-82
lines changed

src/lib/components/composites/list/NamedList.svelte

+13-3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
showNumberOfListItems?: boolean;
1313
numberOfItems?: number;
1414
emptyHint?: string;
15+
errorHint?: string;
16+
preListContent?: Snippet;
1517
}
1618
1719
const {
@@ -22,7 +24,9 @@
2224
numberOfSkeletons,
2325
showNumberOfListItems = false,
2426
numberOfItems = undefined,
25-
emptyHint = "",
27+
emptyHint = "No items found.",
28+
errorHint,
29+
preListContent = undefined,
2630
}: NamedListProps = $props();
2731
</script>
2832

@@ -49,14 +53,18 @@ If the option showNumberOfListItems is set to true (default: false),
4953
the number of list items (either given by 'numberOfItems' or automatically determined)
5054
is added to the list name / header, like 'yourListName (10)'.
5155
52-
While the list is loading, it displays <numberOfSkeleton> skeleton list items.
56+
While the list is loading, it displays \<numberOfSkeleton\> skeleton list items.
5357
If the loading was successful it either shows the components, filled with the component data
5458
or an optional hint (provided with 'emptyHint') that the list is empty.
5559
Otherwise the error message is shown.
60+
61+
You can render additional content between the title and the list by providing `preListContent`.
62+
This can be e.g. a search bar.
5663
-->
5764
<div class="flex flex-col h-full w-full px-5 gap-y-5 overflow-hidden">
5865
{#await items}
5966
<h2>{listName}</h2>
67+
{@render preListContent?.()}
6068
<ul class="space-y-4 pb-1 scroll-box">
6169
<!-- eslint-disable-next-line @typescript-eslint/no-unused-vars -->
6270
{#each Array(numberOfSkeletons) as _}
@@ -71,6 +79,7 @@ Otherwise the error message is shown.
7179
{:else}
7280
<h2>{listName}</h2>
7381
{/if}
82+
{@render preListContent?.()}
7483
{#if loadedItems.length === 0}
7584
<span class="text-hint italic">{emptyHint}</span>
7685
{:else}
@@ -83,10 +92,11 @@ Otherwise the error message is shown.
8392
</ul>
8493
{/if}
8594
{:catch error}
95+
{console.error(`Could not load items: ${error}`)}
8696
<h2>{listName}</h2>
8797
<div class="flex flex-row items-center gap-x-2 p-4">
8898
<CircleAlert size={20} class="text-neutral-500" />
89-
<span class="text-error">{error}</span>
99+
<span class="text-error">{errorHint ? errorHint : error}</span>
90100
</div>
91101
{/await}
92102
</div>

src/lib/components/composites/paper-components/PaperListEntry.svelte

+14-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<script lang="ts">
22
import PaperInfo from "$lib/components/composites/paper-components/PaperInfo.svelte";
3-
import { type PaperListEntryInterface } from "$lib/model/general";
3+
import { asPaper, type PaperListEntryInterface } from "$lib/model/general";
44
import UserAvatar from "$lib/components/composites/user-avatar/UserAvatar.svelte";
55
import { goto } from "$app/navigation";
66
import { PaperDecision } from "$lib/model/api/project";
@@ -11,12 +11,19 @@
1111
onClick?: () => void;
1212
};
1313
14-
const navigateToPaperView = () => goto(`/project/${projectId}/paper/${projectPaper.id}`);
14+
const navigateToPaperView = () => {
15+
const paperId = asPaper(paper).id;
16+
const paperLink =
17+
projectId !== undefined
18+
? `/project/${projectId}/paper/${paperId}`
19+
: `/paper/${paperId}`;
20+
goto(paperLink);
21+
};
1522
1623
const {
17-
projectPaper,
24+
paper,
1825
projectId,
19-
showReviewStatus = false,
26+
showReviewStatus,
2027
onClick = navigateToPaperView,
2128
}: PaperListEntryProps = $props();
2229
@@ -97,13 +104,13 @@ Usage:
97104
>
98105
<div
99106
class="flex flex-auto {showReviewStatus
100-
? `border-l-4 ${getReviewDecisionColor(projectPaper.decision, projectPaper.reviews.length)}`
107+
? `border-l-4 ${getReviewDecisionColor(paper.decision, paper.reviews.length)}`
101108
: ''} rounded-md px-3 py-1.5"
102109
>
103-
<PaperInfo loadingPaper={Promise.resolve(projectPaper.paper!)} />
110+
<PaperInfo loadingPaper={Promise.resolve(asPaper(paper))} />
104111
</div>
105112
{#if showReviewStatus}
106-
{#each projectPaper.reviews as review}
113+
{#each paper.reviews as review}
107114
{#await getReviewUserById(review.userId) then user}
108115
<UserAvatar {user} reviewDecision={review.decision} />
109116
{/await}

src/lib/components/composites/paper-components/paper-view/PaperView.svelte

+18-6
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,13 @@
99
import PaperNavigationButton from "./PaperNavigationButton.svelte";
1010
import type { User } from "$lib/model/api/user";
1111
import type { Paper } from "$lib/model/api/paper";
12+
import type { Project_Paper } from "$lib/model/api/project";
13+
import { asPaper } from "$lib/model/general";
14+
import type { ReferencesAndCitationsCardContentProps } from "./cards/ReferencesAndCitationsCardContent.svelte";
1215
13-
interface Props {
16+
type Props = ReferencesAndCitationsCardContentProps & {
1417
user: User;
15-
loadingPaper: Promise<Paper>;
18+
loadingPaper: Promise<Project_Paper | Paper>;
1619
showButtonBar?: boolean;
1720
backRef: string;
1821
userConfig: {
@@ -21,26 +24,29 @@
2124
};
2225
allowEditModeToggle?: boolean;
2326
startInEditMode?: boolean;
24-
}
27+
};
2528
2629
const {
2730
user,
28-
loadingPaper,
31+
loadingPaper: initialLoadingPaper,
32+
backwardReferencedPapers,
33+
forwardReferencedPapers,
2934
showButtonBar = false,
3035
backRef,
3136
userConfig,
3237
allowEditModeToggle = false,
3338
startInEditMode = false,
3439
}: Props = $props();
3540
41+
let loadingPaper = initialLoadingPaper.then(asPaper);
3642
let loadingPaperId = loadingPaper.then((paper) => paper.id);
3743
</script>
3844

3945
<!--
4046
@component
4147
Whole page component to display information about a paper.
4248
In the bottom, there are buttons to accept, decline or mark the paper as undecided.
43-
Additonally, there are buttons to navigate to the previous or next paper.
49+
Additionally, there are buttons to navigate to the previous or next paper.
4450
4551
- when `showButtonBar` is false, then no buttons are shown at the bottom of the page
4652
- when `userConfig.isReviewMode` is false, then no decision buttons are shown
@@ -56,6 +62,8 @@ Usage:
5662
<PaperView
5763
user={user}
5864
loadingPaper={loadingPaper}
65+
backwardReferencedPapers={backwardReferencedPapers}
66+
forwardReferencedPapers={forwardReferencedPapers}
5967
showButtonBar
6068
backRef="/"
6169
userConfig={{
@@ -75,7 +83,11 @@ Usage:
7583
<main class="flex flex-col h-full w-full px-2 py-4 gap-5">
7684
<div class="flex flex-row w-full h-full gap-5">
7785
<PaperDetailsCard {loadingPaper} {allowEditModeToggle} {startInEditMode} />
78-
<PaperResearchContextCard />
86+
<PaperResearchContextCard
87+
inReviewMode={userConfig.isReviewMode}
88+
{backwardReferencedPapers}
89+
{forwardReferencedPapers}
90+
/>
7991
</div>
8092
{#if showButtonBar}
8193
<div class="flex flex-row w-full h-fit justify-between gap-4" data-testid="button-bar">

src/lib/components/composites/paper-components/paper-view/cards/PaperCard.svelte

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
<!-- Use PaperCardContent elements as children with values according to the tabs props -->
2020
<!--
2121
@component
22-
Paper Card used in the Paper View component.
22+
Paper Card used in the `PaperView` component.
2323
2424
For each tab in the tabs prop, a tab is created with the label and value of the tab.
2525
The children of the PaperCard component are rendered in the content of the tab.
@@ -41,7 +41,7 @@ Usage:
4141
{...restProps}
4242
>
4343
<section class="flex flex-col h-full w-full">
44-
<Tabs.Root value={tabs.length == 0 ? "" : tabs[0].value} class="flex flex-col h-full">
44+
<Tabs.Root value={tabs.length === 0 ? "" : tabs[0].value} class="flex flex-col h-full">
4545
<UnderlineTabsList {tabs} />
4646
<Card.Content class="p-5 flex flex-col h-full">
4747
{@render children()}

src/lib/components/composites/paper-components/paper-view/cards/PaperCardContent.svelte

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<!-- flex cannot be applied to the Tabs.Content element directly, which is why the content is wrapped in another div -->
1414
<!--
1515
@component
16-
Card content used in the Paper Card component.
16+
Card content used in the `PaperCard` component.
1717
1818
Usage:
1919
```svelte

src/lib/components/composites/paper-components/paper-view/cards/PaperDetailsCard.svelte

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@
8686

8787
<!--
8888
@component
89-
Paper Card for paper details in the Paper View component.
89+
`PaperCard` for displaying the details of a paper in the `PaperView` component.
9090
9191
Usage:
9292
```svelte
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,73 @@
11
<script lang="ts">
22
import PaperCard from "./PaperCard.svelte";
33
import PaperCardContent from "./PaperCardContent.svelte";
4+
import ReferencesAndCitationsCardContent, {
5+
type ReferencesAndCitationsCardContentProps,
6+
} from "./ReferencesAndCitationsCardContent.svelte";
47
5-
const tabs = [
6-
{ value: "1", label: "Forward/Backward References" },
7-
{ value: "2", label: "Review Information" },
8-
];
8+
type Props = {
9+
inReviewMode: boolean;
10+
} & ReferencesAndCitationsCardContentProps;
11+
12+
let { inReviewMode, backwardReferencedPapers, forwardReferencedPapers }: Props = $props();
13+
14+
const tabs = inReviewMode
15+
? [
16+
{ value: "1", label: "Review Information" },
17+
{ value: "2", label: "Forward/Backward References" },
18+
]
19+
: [
20+
{ value: "1", label: "Forward/Backward References" },
21+
{ value: "2", label: "Review Information" },
22+
];
923
</script>
1024

1125
<!--
1226
@component
13-
Paper Card for paper research context in the Paper View component.
27+
`PaperCard` for displaying the review information and forward/backward references of a paper in the `PaperView` component.
1428
1529
Usage:
1630
```svelte
17-
<PaperResearchContextCard />
31+
<PaperResearchContextCard {inReviewMode} {backwardReferencedPapers} {forwardReferencedPapers} />
1832
```
1933
-->
2034
<PaperCard {tabs}>
2135
<PaperCardContent value="1">
22-
<span
23-
>Will be implemented in <a
24-
class="text-blue-400"
25-
href="https://github.com/SE-UUlm/snowballr-frontend/issues/42">#42</a
26-
>.</span
27-
>
36+
{#if inReviewMode}
37+
<span>
38+
Will be implemented in
39+
<a
40+
class="text-blue-400"
41+
href="https://github.com/SE-UUlm/snowballr-frontend/issues/53"
42+
>
43+
#53
44+
</a>
45+
.
46+
</span>
47+
{:else}
48+
<ReferencesAndCitationsCardContent
49+
{backwardReferencedPapers}
50+
{forwardReferencedPapers}
51+
/>
52+
{/if}
2853
</PaperCardContent>
2954
<PaperCardContent value="2">
30-
<span
31-
>Will be implemented in <a
32-
class="text-blue-400"
33-
href="https://github.com/SE-UUlm/snowballr-frontend/issues/45">#45</a
34-
>.</span
35-
>
55+
{#if inReviewMode}
56+
<ReferencesAndCitationsCardContent
57+
{backwardReferencedPapers}
58+
{forwardReferencedPapers}
59+
/>
60+
{:else}
61+
<span>
62+
Will be implemented in
63+
<a
64+
class="text-blue-400"
65+
href="https://github.com/SE-UUlm/snowballr-frontend/issues/45"
66+
>
67+
#45
68+
</a>
69+
.
70+
</span>
71+
{/if}
3672
</PaperCardContent>
3773
</PaperCard>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<script lang="ts">
2+
import NamedList from "$lib/components/composites/list/NamedList.svelte";
3+
import SearchBar from "$lib/components/composites/search-bar/SearchBar.svelte";
4+
import PaperListEntry from "../../PaperListEntry.svelte";
5+
import PaperListEntrySkeleton from "../../PaperListEntrySkeleton.svelte";
6+
import type { Paper } from "$lib/model/api/paper";
7+
import { filterPapers } from "$lib/utils/filters";
8+
9+
export interface ReferencesAndCitationsCardContentProps {
10+
backwardReferencedPapers: Promise<Paper[]>;
11+
forwardReferencedPapers: Promise<Paper[]>;
12+
}
13+
14+
let {
15+
backwardReferencedPapers: allBackwardReferencedPapers,
16+
forwardReferencedPapers: allForwardReferencedPapers,
17+
}: ReferencesAndCitationsCardContentProps = $props();
18+
19+
let backwardReferencedPapers = $state<Promise<Paper[]>>(allBackwardReferencedPapers);
20+
let forwardReferencedPapers = $state<Promise<Paper[]>>(allForwardReferencedPapers);
21+
22+
function filterBackwardReferencedPapers(searchText: string) {
23+
backwardReferencedPapers = allBackwardReferencedPapers.then((allPapers) =>
24+
filterPapers(allPapers, searchText),
25+
);
26+
}
27+
28+
function filterForwardReferencedPapers(searchText: string) {
29+
forwardReferencedPapers = allForwardReferencedPapers.then((allPapers) =>
30+
filterPapers(allPapers, searchText),
31+
);
32+
}
33+
</script>
34+
35+
<!--
36+
@component
37+
Card Content for references and citations of a paper, used by `PaperResearchContextCard`.
38+
39+
Usage:
40+
```svelte
41+
<ReferencesAndCitationsCardContent {backwardReferencedPapers} {forwardReferencedPapers} />
42+
```
43+
-->
44+
<section class="flex flex-col h-full gap-5">
45+
<div class="flex h-full overflow-hidden flex-[1_1_0]">
46+
<NamedList
47+
listName="References"
48+
items={backwardReferencedPapers}
49+
showNumberOfListItems
50+
numberOfSkeletons={3}
51+
emptyHint="No references found."
52+
errorHint="Couldn't load references."
53+
>
54+
{#snippet preListContent()}
55+
<SearchBar onSearch={filterBackwardReferencedPapers} timeoutInMs={0} />
56+
{/snippet}
57+
{#snippet listItemComponent(paper)}
58+
<PaperListEntry {paper} projectId={undefined} showReviewStatus={false} />
59+
{/snippet}
60+
{#snippet listItemSkeleton()}
61+
<PaperListEntrySkeleton />
62+
{/snippet}
63+
</NamedList>
64+
</div>
65+
<div class="flex h-full overflow-hidden flex-[1_1_0]">
66+
<NamedList
67+
listName="Citations"
68+
items={forwardReferencedPapers}
69+
showNumberOfListItems
70+
numberOfSkeletons={3}
71+
emptyHint="No citations found."
72+
errorHint="Couldn't load citations."
73+
>
74+
{#snippet preListContent()}
75+
<SearchBar onSearch={filterForwardReferencedPapers} timeoutInMs={0} />
76+
{/snippet}
77+
{#snippet listItemComponent(paper)}
78+
<PaperListEntry {paper} projectId={undefined} showReviewStatus={false} />
79+
{/snippet}
80+
{#snippet listItemSkeleton()}
81+
<PaperListEntrySkeleton />
82+
{/snippet}
83+
</NamedList>
84+
</div>
85+
</section>

0 commit comments

Comments
 (0)