-
Notifications
You must be signed in to change notification settings - Fork 968
chore: add managed ai usage consumption to license view #18934
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 5 commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
e54de1c
initial implementation
ibetitsmike 74ff038
layout adjustments for representing managed agents consumption
ibetitsmike 2e87ac2
improve params to license settings page
ibetitsmike bcb7faa
lint fixes
ibetitsmike 9d58c44
layout fixes on small screen and PR review
ibetitsmike 721561b
- changed ManagedAgentsConsumption component to only have a managedAg…
ibetitsmike 873a1a3
removed Emotion styles and added different colouring based on the usa…
ibetitsmike c893257
fmt fixes
ibetitsmike ba22be6
reverted the orange/red based on usage
ibetitsmike f33f393
reworded docs
ibetitsmike d65392b
fmt lint
ibetitsmike f44e42f
type narrowing
aslilac 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
61 changes: 61 additions & 0 deletions
61
...rc/pages/DeploymentSettingsPage/LicensesSettingsPage/ManagedAgentsConsumption.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,61 @@ | ||
import type { Meta, StoryObj } from "@storybook/react"; | ||
import { ManagedAgentsConsumption } from "./ManagedAgentsConsumption"; | ||
|
||
const meta: Meta<typeof ManagedAgentsConsumption> = { | ||
title: | ||
"pages/DeploymentSettingsPage/LicensesSettingsPage/ManagedAgentsConsumption", | ||
ibetitsmike marked this conversation as resolved.
Show resolved
Hide resolved
|
||
component: ManagedAgentsConsumption, | ||
args: { | ||
usage: 50000, | ||
included: 60000, | ||
limit: 120000, | ||
startDate: "February 27, 2025", | ||
endDate: "February 27, 2026", | ||
}, | ||
}; | ||
|
||
export default meta; | ||
type Story = StoryObj<typeof ManagedAgentsConsumption>; | ||
|
||
export const Default: Story = {}; | ||
|
||
export const NearLimit: Story = { | ||
args: { | ||
usage: 115000, | ||
included: 60000, | ||
limit: 120000, | ||
}, | ||
}; | ||
|
||
export const OverIncluded: Story = { | ||
args: { | ||
usage: 80000, | ||
included: 60000, | ||
limit: 120000, | ||
}, | ||
}; | ||
|
||
export const LowUsage: Story = { | ||
args: { | ||
usage: 25000, | ||
included: 60000, | ||
limit: 120000, | ||
}, | ||
}; | ||
|
||
export const IncludedAtLimit: Story = { | ||
args: { | ||
usage: 25000, | ||
included: 30500, | ||
limit: 30500, | ||
}, | ||
}; | ||
|
||
export const Disabled: Story = { | ||
args: { | ||
enabled: false, | ||
usage: Number.NaN, | ||
included: Number.NaN, | ||
limit: Number.NaN, | ||
}, | ||
}; |
205 changes: 205 additions & 0 deletions
205
site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/ManagedAgentsConsumption.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,205 @@ | ||
import type { Interpolation, Theme } from "@emotion/react"; | ||
import MuiLink from "@mui/material/Link"; | ||
import { Button } from "components/Button/Button"; | ||
import { | ||
Collapsible, | ||
CollapsibleContent, | ||
CollapsibleTrigger, | ||
} from "components/Collapsible/Collapsible"; | ||
import { Stack } from "components/Stack/Stack"; | ||
import dayjs from "dayjs"; | ||
import { ChevronRightIcon } from "lucide-react"; | ||
import type { FC } from "react"; | ||
|
||
interface ManagedAgentsConsumptionProps { | ||
usage: number; | ||
included: number; | ||
limit: number; | ||
startDate: string; | ||
endDate: string; | ||
enabled?: boolean; | ||
} | ||
|
||
export const ManagedAgentsConsumption: FC<ManagedAgentsConsumptionProps> = ({ | ||
usage, | ||
included, | ||
limit, | ||
startDate, | ||
endDate, | ||
enabled = true, | ||
}) => { | ||
if (!enabled) { | ||
return ( | ||
<div css={styles.disabledRoot}> | ||
<Stack alignItems="center" spacing={1}> | ||
<Stack alignItems="center" spacing={0.5}> | ||
<span css={styles.disabledTitle}> | ||
Managed AI Agents Disabled | ||
</span> | ||
<span css={styles.disabledDescription}> | ||
Managed AI agents are not included in your current license. | ||
Contact{" "} | ||
<MuiLink href="mailto:sales@coder.com">sales</MuiLink> to upgrade | ||
your license and unlock this feature. | ||
</span> | ||
</Stack> | ||
</Stack> | ||
</div> | ||
); | ||
} | ||
|
||
const usagePercentage = Math.min((usage / limit) * 100, 100); | ||
const includedPercentage = Math.min((included / limit) * 100, 100); | ||
const remainingPercentage = Math.max(100 - includedPercentage, 0); | ||
|
||
return ( | ||
<section className="border border-solid rounded"> | ||
<div className="p-4"> | ||
<Collapsible> | ||
<header className="flex flex-col gap-2 items-start"> | ||
<h3 className="text-md m-0 font-medium"> | ||
Managed agents consumption | ||
ibetitsmike marked this conversation as resolved.
Show resolved
Hide resolved
|
||
</h3> | ||
|
||
<CollapsibleTrigger asChild> | ||
<Button | ||
className={` | ||
h-auto p-0 border-0 bg-transparent font-medium text-content-secondary | ||
hover:bg-transparent hover:text-content-primary | ||
[&[data-state=open]_svg]:rotate-90 | ||
`} | ||
> | ||
<ChevronRightIcon /> | ||
How we calculate managed agents consumption | ||
</Button> | ||
</CollapsibleTrigger> | ||
</header> | ||
|
||
<CollapsibleContent | ||
className={` | ||
pt-2 pl-7 pr-5 space-y-4 font-medium max-w-[720px] | ||
text-sm text-content-secondary | ||
[&_p]:m-0 [&_ul]:m-0 [&_ul]:p-0 [&_ul]:list-none | ||
`} | ||
> | ||
<p> | ||
Managed agents are counted based on the amount of successfully | ||
started workspaces with an AI agent. | ||
ibetitsmike marked this conversation as resolved.
Show resolved
Hide resolved
|
||
</p> | ||
<ul> | ||
<li className="flex items-center gap-2"> | ||
<div | ||
className="rounded-[2px] bg-highlight-green size-3 inline-block" | ||
aria-label="Legend for current usage in the chart" | ||
/> | ||
Amount of started workspaces with an AI agent. | ||
ibetitsmike marked this conversation as resolved.
Show resolved
Hide resolved
|
||
</li> | ||
<li className="flex items-center gap-2"> | ||
<div | ||
className="rounded-[2px] bg-content-disabled size-3 inline-block" | ||
aria-label="Legend for included allowance in the chart" | ||
/> | ||
Included allowance from your current license plan. | ||
ibetitsmike marked this conversation as resolved.
Show resolved
Hide resolved
|
||
</li> | ||
<li className="flex items-center gap-2"> | ||
<div | ||
className="size-3 inline-flex items-center justify-center" | ||
aria-label="Legend for total limit in the chart" | ||
> | ||
<div className="w-full border-b-1 border-t-1 border-dashed border-content-disabled" /> | ||
</div> | ||
Total limit after which further AI workspace builds will be blocked. | ||
</li> | ||
</ul> | ||
</CollapsibleContent> | ||
</Collapsible> | ||
</div> | ||
|
||
<div className="p-6 border-0 border-t border-solid"> | ||
<div className="flex justify-between text-sm text-content-secondary mb-4"> | ||
<span> | ||
{startDate ? dayjs(startDate).format("MMMM D, YYYY") : ""} | ||
</span> | ||
<span>{endDate ? dayjs(endDate).format("MMMM D, YYYY") : ""}</span> | ||
</div> | ||
|
||
<div className="relative h-6 bg-surface-secondary rounded overflow-hidden"> | ||
<div | ||
className="absolute top-0 left-0 h-full bg-highlight-green transition-all duration-300" | ||
style={{ width: `${usagePercentage}%` }} | ||
/> | ||
|
||
<div | ||
className="absolute top-0 h-full bg-content-disabled opacity-30" | ||
style={{ | ||
left: `${includedPercentage}%`, | ||
width: `${remainingPercentage}%`, | ||
}} | ||
/> | ||
</div> | ||
|
||
<div className="relative hidden lg:flex justify-between mt-4 text-sm"> | ||
<div className="flex flex-col items-start"> | ||
<span className="text-content-secondary">Actual:</span> | ||
<span className="font-medium">{usage.toLocaleString()}</span> | ||
</div> | ||
|
||
<div | ||
className="absolute flex flex-col items-center transform -translate-x-1/2" | ||
style={{ | ||
left: `${Math.max(Math.min(includedPercentage, 90), 10)}%`, | ||
}} | ||
> | ||
<span className="text-content-secondary">Included:</span> | ||
<span className="font-medium">{included.toLocaleString()}</span> | ||
</div> | ||
|
||
<div className="flex flex-col items-end"> | ||
<span className="text-content-secondary">Limit:</span> | ||
<span className="font-medium">{limit.toLocaleString()}</span> | ||
</div> | ||
</div> | ||
|
||
<div className="flex lg:hidden flex-col gap-3 mt-4 text-sm"> | ||
<div className="flex justify-between"> | ||
<div className="flex flex-col items-start"> | ||
<span className="text-content-secondary">Actual:</span> | ||
<span className="font-medium">{usage.toLocaleString()}</span> | ||
</div> | ||
<div className="flex flex-col items-center"> | ||
<span className="text-content-secondary">Included:</span> | ||
<span className="font-medium">{included.toLocaleString()}</span> | ||
</div> | ||
<div className="flex flex-col items-end"> | ||
<span className="text-content-secondary">Limit:</span> | ||
<span className="font-medium">{limit.toLocaleString()}</span> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</section> | ||
); | ||
}; | ||
|
||
const styles = { | ||
disabledTitle: { | ||
fontSize: 16, | ||
}, | ||
|
||
disabledRoot: (theme) => ({ | ||
minHeight: 240, | ||
display: "flex", | ||
alignItems: "center", | ||
justifyContent: "center", | ||
borderRadius: 8, | ||
border: `1px solid ${theme.palette.divider}`, | ||
padding: 48, | ||
}), | ||
|
||
disabledDescription: (theme) => ({ | ||
color: theme.palette.text.secondary, | ||
textAlign: "center", | ||
maxWidth: 464, | ||
marginTop: 8, | ||
}), | ||
} satisfies Record<string, Interpolation<Theme>>; |
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.
Uh oh!
There was an error while loading. Please reload this page.