-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add epic list view #77
Merged
Merged
Changes from all commits
Commits
Show all changes
30 commits
Select commit
Hold shift + click to select a range
b712729
Refactor user types
maximilianruesch f9db363
Add create issue for server
maximilianruesch 106a19a
Fix create issue for cloud
maximilianruesch f940580
Add jira server info to provider class
maximilianruesch 52aebb7
Add implementation for executing api calls in a versioned manner
maximilianruesch 5494f24
Add test implementation for getIssueTypesWithFieldsMap
maximilianruesch 60f7867
Fix issues with changed types
maximilianruesch db70900
Merge branch 'task/fix-create-issue-for-server' into refactor/impleme…
maximilianruesch 874a2aa
Add error when jira server version is unsupported
maximilianruesch 51dc1b3
Fix server provider for creating epics
maximilianruesch 5e9c1a4
started implementation of Epic View
trueliquid 4669222
implements Button to access Epic List View
trueliquid ff4f822
Removed Search Bar for now
trueliquid 37ad385
Added Button to open Epic View
trueliquid 39fafcf
Added Epic Card
trueliquid cd239e3
Added Create Epic Button to Epic View
trueliquid 571c669
Epic List View shows epics missing type and status
trueliquid 9f53b21
Removed Issue Type and status label since it is not in the mockup
trueliquid 12c01b8
accidentally removed summary text on epic card
trueliquid d1f7efc
Merge branch 'task/fix-create-issue-for-server' into refactor/impleme…
maximilianruesch 5c385da
Merge branch 'main' into refactor/implement-different-implementations…
maximilianruesch 56a348f
Merge branch 'refactor/implement-different-implementations-for-server…
maximilianruesch 6663b0f
Revert accidental changes
maximilianruesch 76101a2
Formatting and remove redundant code
trueliquid d41db66
Remove code used for epic search
trueliquid cb455ce
Merge remote-tracking branch 'origin/story/Fast-Epic-List-View' into …
trueliquid 0f1a562
Merge branch 'refactor/implement-different-implementations-for-server…
maximilianruesch bb62626
Merge branch 'main' into story/Fast-Epic-List-View
maximilianruesch bb0296f
Fix linting issues
maximilianruesch 5013be1
Fix linting issues again
maximilianruesch File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
import {Issue} from "types"; | ||
import { | ||
Avatar, | ||
Badge, | ||
Box, | ||
Center, | ||
Grid, | ||
Group, | ||
Modal, | ||
Stack, | ||
Text, ThemeIcon, | ||
Tooltip, | ||
useMantineTheme | ||
} from "@mantine/core"; | ||
import {useHover} from "@mantine/hooks"; | ||
import {useState} from "react"; | ||
import {useQueryClient} from "@tanstack/react-query"; | ||
import {IconBolt} from "@tabler/icons"; | ||
import {DeleteButton} from "../BacklogView/Issue/DeleteButton"; | ||
|
||
export function EpicCard ({ | ||
issueKey, | ||
summary, | ||
status, | ||
storyPointsEstimate, | ||
epic, | ||
labels, | ||
assignee, | ||
}: Issue) { | ||
let storyPointsColor: string | ||
const [opened, setOpened] = useState(false) | ||
const queryClient = useQueryClient() | ||
const {hovered} = useHover() | ||
const theme = useMantineTheme() | ||
const hoverStyles = | ||
theme.colorScheme === "dark" | ||
? { | ||
backgroundColor: theme.colors.dark[8], | ||
transition: "background-color .1s ease-in", | ||
} | ||
: { | ||
backgroundColor: theme.colors.gray[1], | ||
transition: "background-color .1s ease-in", | ||
} | ||
switch (status) { | ||
case "To Do": | ||
storyPointsColor = "gray.6" | ||
break | ||
case "In Progress": | ||
storyPointsColor = "blue.8" | ||
break | ||
case "Done": | ||
storyPointsColor = "green.9" | ||
break | ||
default: | ||
storyPointsColor = "gray.6" | ||
} | ||
return ( | ||
<> | ||
<DeleteButton mounted={hovered} issueKey={issueKey} /> | ||
<Grid | ||
columns={100} | ||
p={3} | ||
sx={{ | ||
borderRadius: theme.radius.sm, | ||
margin: 0, | ||
boxShadow: theme.shadows.xs, | ||
transition: "background-color .8s ease-out", | ||
":hover": hoverStyles, | ||
}} | ||
> | ||
<Grid.Col | ||
span={8} | ||
sx={{ | ||
display: "flex", | ||
flexDirection: "column", | ||
justifyContent: "center", | ||
}} | ||
> | ||
<Center> | ||
<ThemeIcon | ||
size="sm" | ||
variant="gradient" | ||
gradient={{ from: "violet", to: "white", deg: 105 }} | ||
> | ||
<IconBolt/> | ||
</ThemeIcon> | ||
</Center> | ||
</Grid.Col> | ||
<Grid.Col span={74}> | ||
<Stack spacing={0}> | ||
<Group spacing={2}> | ||
<Text | ||
size="sm" | ||
mr={5} | ||
color="blue" | ||
td={status === "Done" ? "line-through" : "none"} | ||
sx={{ | ||
":hover": { | ||
textDecoration: "underline", | ||
cursor: "pointer", | ||
}, | ||
}} | ||
> | ||
{issueKey} | ||
</Text> | ||
{epic && ( | ||
<Badge mr={5} color="violet"> | ||
{epic} | ||
</Badge> | ||
)} | ||
{labels?.length !== 0 && | ||
labels.map((label) => ( | ||
<Badge | ||
mr={2} | ||
key={`${issueKey}-${label}`} | ||
color="yellow" | ||
> | ||
{label} | ||
</Badge> | ||
))} | ||
</Group> | ||
<Text size="lg">{summary}</Text> | ||
</Stack> | ||
</Grid.Col> | ||
<Grid.Col | ||
span={8} | ||
sx={{ | ||
display: "flex", | ||
flexDirection: "column", | ||
justifyContent: "center", | ||
}} | ||
> | ||
<Tooltip | ||
label={ | ||
assignee?.displayName !== undefined | ||
? assignee.displayName | ||
: "unassigned" | ||
} | ||
> | ||
{assignee?.avatarUrls !== undefined ? ( | ||
<Avatar | ||
src={assignee.avatarUrls["24x24"]} | ||
size="sm" | ||
radius="xl" | ||
ml={4} | ||
mr={4} | ||
/> | ||
) : ( | ||
<Avatar | ||
radius="xl" | ||
variant="outline" | ||
size="sm" | ||
ml={4} | ||
mr={4} | ||
/> | ||
)} | ||
</Tooltip> | ||
</Grid.Col> | ||
<Grid.Col span={3}> | ||
<Box sx={{ alignSelf: "flex-start" }}> | ||
<Badge | ||
w="24px" | ||
p="0px" | ||
bg={ | ||
storyPointsEstimate !== undefined && | ||
storyPointsEstimate !== null | ||
? storyPointsColor | ||
: "transparent" | ||
} | ||
variant="filled" | ||
> | ||
{storyPointsEstimate} | ||
</Badge> | ||
</Box> | ||
</Grid.Col> | ||
</Grid> | ||
<Modal | ||
opened={opened} | ||
onClose={() => { | ||
setOpened(false) | ||
queryClient.invalidateQueries({ queryKey: ["issues"] }) | ||
}} | ||
size="90vw" | ||
overflow="outside" | ||
overlayOpacity={0.55} | ||
overlayBlur={3} | ||
withCloseButton={false} | ||
> | ||
{/* TODO open Epic Detail View */} | ||
</Modal> | ||
</> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
import {Group, Stack, Text, Title, ScrollArea, Box, Button, Center, Loader} from "@mantine/core"; | ||
import {useNavigate} from "react-router-dom"; | ||
import {useState} from "react"; | ||
import {useQuery} from "@tanstack/react-query"; | ||
import {useCanvasStore} from "../../lib/Store"; | ||
import {CreateIssueModal} from "../CreateIssue/CreateIssueModal"; | ||
import {Issue} from "../../../types"; | ||
import {EpicWrapper} from "./EpicWrapper"; | ||
import {getEpics} from "./helpers/queryFetchers"; | ||
|
||
|
||
export function EpicView() { | ||
const navigate = useNavigate() | ||
const projectName = useCanvasStore((state) => state.selectedProject?.name) | ||
const [createIssueModalOpened, setCreateIssueModalOpened] = useState(false) | ||
const projectKey = useCanvasStore((state) => state.selectedProject?.key) | ||
const [EpicWrappers, setEpicWrappers] = useState( | ||
new Map<string, { issues: Issue[]}>() | ||
) | ||
|
||
const updateEpicWrapper = ( | ||
key: string, | ||
value: { issues: Issue[]} | ||
) => { | ||
setEpicWrappers((map) => new Map(map.set(key, value))) | ||
} | ||
|
||
const {isLoading: isLoadingEpics} = | ||
useQuery({ | ||
queryKey: ["epics", projectKey], | ||
queryFn: () => getEpics(projectKey), | ||
enabled: !!projectKey, | ||
onSuccess: (epics) => { | ||
updateEpicWrapper("EpicView", { | ||
issues: | ||
epics && epics instanceof Array ? epics : [] | ||
}) | ||
}, | ||
}) | ||
if (isLoadingEpics) | ||
return ( | ||
<Center style={{ width: "100%", height: "100%" }}> | ||
{projectKey ? ( | ||
<Loader /> | ||
) : ( | ||
<Stack align="center"> | ||
<Title>No Project has been selected!</Title> | ||
<Text> | ||
Please go back to the Projects View section and select a project | ||
</Text> | ||
<Button onClick={() => navigate("/projectsview")}>Go back</Button> | ||
</Stack> | ||
)} | ||
</Center> | ||
) | ||
return ( | ||
<Stack sx={{ minHeight: "100%"}}> | ||
<Stack align="left" spacing={0}> | ||
<Group> | ||
<Group spacing="xs" c="dimmed"> | ||
<Text | ||
onClick={() => navigate("/projectsview")} | ||
sx={{ | ||
":hover": { | ||
textDecoration: "underline", | ||
cursor: "pointer", | ||
}, | ||
}} | ||
> | ||
Projects | ||
</Text> | ||
<Text>/</Text> | ||
<Text>{projectName}</Text> | ||
</Group> | ||
</Group> | ||
<Title mb="sm">Epics</Title> | ||
</Stack> | ||
<ScrollArea.Autosize | ||
className="main-panel" | ||
maxHeight="calc(100vh - 230px)" | ||
w="100%" | ||
p="sm" | ||
sx={{ | ||
minWidth: "260px", | ||
}} | ||
> | ||
{EpicWrappers.get("EpicView") &&( | ||
<Box mr="xs"> | ||
<EpicWrapper epics={EpicWrappers.get("EpicView")!.issues}/> | ||
</Box> | ||
)} | ||
<Box mr="xs"> | ||
<Button | ||
mt="sm" | ||
mb="xl" | ||
variant="subtle" | ||
color="gray" | ||
radius="sm" | ||
display="flex" | ||
fullWidth | ||
onClick={() => setCreateIssueModalOpened(true)} | ||
sx={(theme) => ({ | ||
justifyContent: "left", | ||
":hover": { | ||
background: | ||
theme.colorScheme === "dark" | ||
? theme.colors.dark[4] | ||
: theme.colors.gray[4], | ||
}, | ||
})} | ||
> | ||
+ Create Epic | ||
</Button> | ||
</Box> | ||
<CreateIssueModal | ||
opened={createIssueModalOpened} | ||
setOpened={setCreateIssueModalOpened} | ||
/> | ||
</ScrollArea.Autosize> | ||
</Stack> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import {Stack} from "@mantine/core"; | ||
import {Issue} from "../../../types"; | ||
import {EpicCard} from "./EpicCard"; | ||
|
||
|
||
export function EpicWrapper({ | ||
epics, | ||
}: { | ||
epics: Issue[] | ||
}){ | ||
return ( | ||
<Stack spacing="sm"> | ||
{epics.map((epic: Issue) => ( | ||
<EpicCard {...epic} key={epic.issueKey} /> | ||
))} | ||
</Stack> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import {Issue} from "../../../../types"; | ||
|
||
export const getEpics = ( | ||
projectKey: string | undefined | ||
): Promise<Issue[]> => | ||
window.provider.getEpicsByProject(projectKey || "") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from "./EpicView" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: Story points box could probably use a refactoring into its own component, but we can add this later.