- Notifications
You must be signed in to change notification settings - Fork948
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
base:main
Are you sure you want to change the base?
Changes fromall commits
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import type { Meta, StoryObj } from "@storybook/react"; | ||
import { ManagedAgentsConsumption } from "./ManagedAgentsConsumption"; | ||
const meta: Meta<typeof ManagedAgentsConsumption> = { | ||
title: | ||
"pages/DeploymentSettingsPage/LicensesSettingsPage/ManagedAgentsConsumption", | ||
Comment on lines +5 to +6 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. I love how the formatter decided to put this on it's own line to wrap it even though it would take more space 🙄 | ||
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 Disabled: Story = { | ||
args: { | ||
usage: Number.NaN, | ||
included: Number.NaN, | ||
limit: Number.NaN, | ||
}, | ||
}; |
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,188 @@ | ||||||||||
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 Agent Feature Disabled | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Suggested change
| ||||||||||
</span> | ||||||||||
<span css={styles.disabledDescription}> | ||||||||||
The managed AI agent feature is not included in your current | ||||||||||
license. Contact{" "} | ||||||||||
Comment on lines +40 to +41 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Suggested change
| ||||||||||
<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 | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. IDK what's better, "managed agents consumption" or "managed agent consumption" (like below). But we should probably stick to one | ||||||||||
</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 agent 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 started | ||||||||||
workspaces with an AI agent. | ||||||||||
Comment on lines +86 to +87 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Suggested change
| ||||||||||
</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. | ||||||||||
</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. | ||||||||||
</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 the feature will be disabled. | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Suggested change
| ||||||||||
</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 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> | ||||||||||
</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>>; |
Uh oh!
There was an error while loading.Please reload this page.