-
Notifications
You must be signed in to change notification settings - Fork 937
feat: implement multi-org template gallery #13784
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
Merged
Merged
Changes from all commits
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
0a5c431
feat: initial changes for multi-org templates page
jaaydenh 6f96fee
feat: add TemplateCard component
jaaydenh 51ebb67
feat: add component stories
jaaydenh a0effc6
chore: update template query naming
jaaydenh be37085
fix: fix formatting
jaaydenh 5649166
feat: template card interaction and navigation
jaaydenh 3ea3aa2
fix: copy updates
jaaydenh f17a0c3
chore: update TemplateFilter type to include FilterQuery
jaaydenh 0077db0
chore: update typesGenerated.ts
jaaydenh 461202e
feat: update template filter api logic
jaaydenh 66e02fb
fix: fix format
jaaydenh 369c59f
fix: get activeOrg
jaaydenh c41cdc4
fix: add format annotation
jaaydenh 7f5d35e
chore: use organization display name
jaaydenh 6e2a6d8
feat: client side org filtering
jaaydenh 978c047
fix: use org display name
jaaydenh aaed038
fix: add ExactName
jaaydenh 8d84ad9
feat: show orgs filter only if more than 1 org
jaaydenh a1c6169
chore: updates for PR review
jaaydenh 15542c0
fix: fix format
jaaydenh 8f4c56f
chore: add story for multi org
jaaydenh a282bac
fix: aggregate templates by organization id
jaaydenh b092644
fix: fix format
jaaydenh 32376e6
fix: check org count
jaaydenh 801138a
fix: update ExactName type
jaaydenh 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or 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
40 changes: 40 additions & 0 deletions
40
site/src/modules/templates/TemplateCard/TemplateCard.stories.tsx
This file contains hidden or 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,40 @@ | ||
import type { Meta, StoryObj } from "@storybook/react"; | ||
import { chromatic } from "testHelpers/chromatic"; | ||
import { MockTemplate } from "testHelpers/entities"; | ||
import { TemplateCard } from "./TemplateCard"; | ||
|
||
const meta: Meta<typeof TemplateCard> = { | ||
title: "modules/templates/TemplateCard", | ||
parameters: { chromatic }, | ||
component: TemplateCard, | ||
args: { | ||
template: MockTemplate, | ||
}, | ||
}; | ||
|
||
export default meta; | ||
type Story = StoryObj<typeof TemplateCard>; | ||
|
||
export const Template: Story = {}; | ||
|
||
export const DeprecatedTemplate: Story = { | ||
args: { | ||
template: { | ||
...MockTemplate, | ||
deprecated: true, | ||
}, | ||
}, | ||
}; | ||
|
||
export const LongContentTemplate: Story = { | ||
args: { | ||
template: { | ||
...MockTemplate, | ||
display_name: "Very Long Template Name", | ||
organization_display_name: "Very Long Organization Name", | ||
description: | ||
"This is a very long test description. This is a very long test description. This is a very long test description. This is a very long test description", | ||
active_user_count: 999, | ||
}, | ||
}, | ||
}; |
144 changes: 144 additions & 0 deletions
144
site/src/modules/templates/TemplateCard/TemplateCard.tsx
This file contains hidden or 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,144 @@ | ||
import type { Interpolation, Theme } from "@emotion/react"; | ||
import ArrowForwardOutlined from "@mui/icons-material/ArrowForwardOutlined"; | ||
import Button from "@mui/material/Button"; | ||
import type { FC, HTMLAttributes } from "react"; | ||
import { Link as RouterLink, useNavigate } from "react-router-dom"; | ||
import type { Template } from "api/typesGenerated"; | ||
import { ExternalAvatar } from "components/Avatar/Avatar"; | ||
import { AvatarData } from "components/AvatarData/AvatarData"; | ||
import { DeprecatedBadge } from "components/Badges/Badges"; | ||
|
||
type TemplateCardProps = HTMLAttributes<HTMLDivElement> & { | ||
template: Template; | ||
}; | ||
|
||
export const TemplateCard: FC<TemplateCardProps> = ({ | ||
template, | ||
...divProps | ||
}) => { | ||
const navigate = useNavigate(); | ||
const templatePageLink = `/templates/${template.name}`; | ||
const hasIcon = template.icon && template.icon !== ""; | ||
|
||
const handleKeyDown = (e: React.KeyboardEvent) => { | ||
if (e.key === "Enter" && e.currentTarget === e.target) { | ||
navigate(templatePageLink); | ||
} | ||
}; | ||
|
||
return ( | ||
<div | ||
css={styles.card} | ||
{...divProps} | ||
role="button" | ||
tabIndex={0} | ||
onClick={() => navigate(templatePageLink)} | ||
onKeyDown={handleKeyDown} | ||
> | ||
<div css={styles.header}> | ||
<div> | ||
<AvatarData | ||
title={ | ||
template.display_name.length > 0 | ||
? template.display_name | ||
: template.name | ||
} | ||
subtitle={template.organization_display_name} | ||
avatar={ | ||
hasIcon && ( | ||
<ExternalAvatar variant="square" fitImage src={template.icon} /> | ||
) | ||
} | ||
/> | ||
</div> | ||
<div> | ||
{template.active_user_count}{" "} | ||
{template.active_user_count === 1 ? "user" : "users"} | ||
</div> | ||
</div> | ||
|
||
<div> | ||
<span css={styles.description}> | ||
<p>{template.description}</p> | ||
</span> | ||
</div> | ||
|
||
<div css={styles.useButtonContainer}> | ||
{template.deprecated ? ( | ||
<DeprecatedBadge /> | ||
) : ( | ||
<Button | ||
component={RouterLink} | ||
css={styles.actionButton} | ||
className="actionButton" | ||
fullWidth | ||
startIcon={<ArrowForwardOutlined />} | ||
title={`Create a workspace using the ${template.display_name} template`} | ||
to={`/templates/${template.name}/workspace`} | ||
onClick={(e) => { | ||
e.stopPropagation(); | ||
}} | ||
> | ||
Create Workspace | ||
</Button> | ||
)} | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
const styles = { | ||
card: (theme) => ({ | ||
width: "320px", | ||
padding: 24, | ||
borderRadius: 6, | ||
border: `1px solid ${theme.palette.divider}`, | ||
textAlign: "left", | ||
color: "inherit", | ||
display: "flex", | ||
flexDirection: "column", | ||
cursor: "pointer", | ||
"&:hover": { | ||
color: theme.experimental.l2.hover.text, | ||
borderColor: theme.experimental.l2.hover.text, | ||
}, | ||
}), | ||
|
||
header: { | ||
display: "flex", | ||
alignItems: "center", | ||
justifyContent: "space-between", | ||
marginBottom: 24, | ||
}, | ||
|
||
icon: { | ||
flexShrink: 0, | ||
paddingTop: 4, | ||
width: 32, | ||
height: 32, | ||
}, | ||
|
||
description: (theme) => ({ | ||
fontSize: 13, | ||
color: theme.palette.text.secondary, | ||
lineHeight: "1.6", | ||
display: "block", | ||
}), | ||
|
||
useButtonContainer: { | ||
display: "flex", | ||
gap: 12, | ||
flexDirection: "column", | ||
paddingTop: 24, | ||
marginTop: "auto", | ||
alignItems: "center", | ||
}, | ||
|
||
actionButton: (theme) => ({ | ||
transition: "none", | ||
color: theme.palette.text.secondary, | ||
"&:hover": { | ||
borderColor: theme.palette.text.primary, | ||
}, | ||
}), | ||
} satisfies Record<string, Interpolation<Theme>>; |
This file contains hidden or 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 hidden or 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 hidden or 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
Oops, something went wrong.
Oops, something went wrong.
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.
super minor nit, I tend to call these sorts of captures
attrs
, but there's definitely precedent for calling itwhateverProps
too. maybe this is something we should consolidate on...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.
I was following the pattern in the files I was working on. In other code bases/the React docs, this is often called ...props as well. I think it depends if we want to call them based on what they are, "props" or how they are used, props on divs "divProps" or attributes on divs "attrs"